<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ZeroOne</title>
    <link>https://zeroone.tistory.com/</link>
    <description>Improve Programming skills</description>
    <language>ko</language>
    <pubDate>Sat, 25 Jul 2026 02:04:36 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>zerone</managingEditor>
    <image>
      <title>ZeroOne</title>
      <url>https://tistory1.daumcdn.net/tistory/4678607/attach/5b55cb7b86d546b898cdc406b4a621b7</url>
      <link>https://zeroone.tistory.com</link>
    </image>
    <item>
      <title>스프링 MVC - 구조 이해</title>
      <link>https://zeroone.tistory.com/56</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;스프링 MVC 전체 구조&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;946&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/spwlL/btrHrNlQ6Ll/HWPVpQdL0jJvADsZUOvkV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/spwlL/btrHrNlQ6Ll/HWPVpQdL0jJvADsZUOvkV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/spwlL/btrHrNlQ6Ll/HWPVpQdL0jJvADsZUOvkV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FspwlL%2FbtrHrNlQ6Ll%2FHWPVpQdL0jJvADsZUOvkV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;415&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;946&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;직접 만든 프레임워크 스프링 &lt;/span&gt;&lt;span&gt;MVC &lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;b&gt;비교&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;FrontController&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-&amp;gt;&amp;nbsp; DispatcherServlet &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;handlerMappingMap&amp;nbsp; -&amp;gt;&amp;nbsp; HandlerMapping &lt;br /&gt;MyHandlerAdapter&amp;nbsp; &amp;nbsp; &amp;nbsp;-&amp;gt;&amp;nbsp; HandlerAdapter &lt;br /&gt;ModelView&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;gt;&amp;nbsp; ModelAndView &lt;br /&gt;viewResolver&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;gt;&amp;nbsp; ViewResolver &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MyView&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-&amp;gt;&amp;nbsp; View &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;동작 순서&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;핸들러 조회&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;핸들러 매핑을 통해 요청 &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;에 매핑된 핸들러&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;컨트롤러&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;를 조회한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;핸들러 어댑터 조회&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;핸들러를 실행할 수 있는 핸들러 어댑터를 조회한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;핸들러 어댑터 실행&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;핸들러 어댑터를 실행한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;핸들러 실행&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;핸들러 어댑터가 실제 핸들러를 실행한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;ModelAndView &lt;/span&gt;&lt;span&gt;반환&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;핸들러 어댑터는 핸들러가 반환하는 정보를 &lt;/span&gt;&lt;span&gt;ModelAndView&lt;/span&gt;&lt;span&gt;로 &lt;/span&gt;&lt;span&gt;변환&lt;/span&gt;&lt;span&gt;해서 &lt;/span&gt;&lt;span&gt;반환한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;viewResolver &lt;/span&gt;&lt;span&gt;호출&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;뷰 리졸버를 찾고 실행한다&lt;/span&gt;&lt;span&gt;. &lt;br /&gt;&lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;의 경우&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;InternalResourceViewResolver &lt;/span&gt;&lt;span&gt;가 자동 등록되고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;사용된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;View &lt;/span&gt;&lt;span&gt;반환&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;뷰 리졸버는뷰의 논리 이름을 물리 이름으로 바꾸고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;렌더링 역할을 담당하는 뷰 객체를&amp;nbsp; &lt;/span&gt;&lt;span&gt;반환한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;JSP&lt;/span&gt;&lt;span&gt;의 경우 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;InternalResourceView(JstlView) &lt;/span&gt;&lt;span&gt;를 반환하는데&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;내부에 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;forward() &lt;/span&gt;&lt;span&gt;로직이 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;뷰 렌더링&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;뷰를 통해서 뷰를 렌더링한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;HandlerMapping(&lt;/span&gt;&lt;span&gt;핸들러 매핑&lt;/span&gt;&lt;span&gt;)&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;핸들러 매핑에서 이 컨트롤러를 찾을 수 있어야 한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;예&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;스프링 빈의 이름으로 핸들러를 찾을 수 있는 핸들러 매핑&lt;/span&gt;&lt;span&gt;이 필요하다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;HandlerAdapter(&lt;/span&gt;&lt;span&gt;핸들러 어댑터&lt;/span&gt;&lt;span&gt;)&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;핸들러 매핑을 통해서 찾은 핸들러를 실행할 수 있는 핸들러 어댑터가 필요하다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;예&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;Controller &lt;/span&gt;&lt;span&gt;인터페이스를 실행할 수 있는 핸들러 어댑터를 찾고 실행해야 한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링은 이미 필요한 핸들러 매핑과 핸들러 어댑터를 대부분 구현해두었다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;개발자가 직접 핸들러 매핑과 핸들러 어댑터를 만드는 일은 거의 없다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;스프링 부트가 자동 등록하는 핸들러 매핑과 핸들러 어댑터&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;실제로는 더 많지만&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;중요한 부분 위주로 설명하기 위해 일부 생략&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HandlerMapping &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0 = RequestMappingHandlerMapping : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용&lt;/li&gt;
&lt;li&gt;1 = BeanNameUrlHandlerMapping : 스프링 빈의 이름으로 핸들러를 찾는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HandlerAdapter &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0 = RequestMappingHandlerAdapter : 애노테이션 기반의 컨트롤러인 @RequestMapping에서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;뷰 리졸버 &lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;b&gt;- InternalResourceViewResolver&lt;/b&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;스프링 부트는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;InternalResourceViewResolver &lt;/span&gt;&lt;span&gt;라는 뷰 리졸버를 자동으로 등록하는데&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;이때 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;application.properties &lt;/span&gt;&lt;span&gt;에 등록한 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;spring.mvc.view.prefix &lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;spring.mvc.view.suffix &lt;/span&gt;&lt;span&gt;설정 정보를 사용해서 등록한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;스프링 부트가 자동 등록하는 뷰 리졸버&lt;/b&gt; &lt;br /&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;실제로는 더 많지만&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;중요한 부분 위주로 설명하기 위해 일부 생략&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 = BeanNameViewResolver : 빈 이름으로 뷰를 찾아서 반환한다. (예: 엑셀 파일 생성 기능에 사용)&lt;/li&gt;
&lt;li&gt;2 = InternalResourceViewResolver : JSP를 처리할 수 있는 뷰를 반환한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;뷰 리졸버 동작 방식&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. &lt;/span&gt;&lt;span&gt;핸들러 어댑터 호출&lt;br /&gt;&lt;/span&gt;&lt;span&gt;핸들러 어댑터를 통해 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;new-form &lt;/span&gt;&lt;span&gt;이라는 논리 뷰 이름을 획득한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. ViewResolver &lt;/span&gt;&lt;span&gt;호출&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;&amp;nbsp; &amp;nbsp; 2-1. new-form &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이라는 뷰 이름으로 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;viewResolver&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;를 순서대로 호출한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;&amp;nbsp; &amp;nbsp; 2-2. BeanNameViewResolver &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;new-form &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이라는 이름의 스프링 빈으로 등록된 뷰를 찾아야 하는데 없다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2-3. &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;InternalResourceViewResolver &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;가 호출된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3. InternalResourceViewResolver &lt;br /&gt;&lt;/span&gt;&lt;span&gt;이 뷰 리졸버는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;InternalResourceView &lt;/span&gt;&lt;span&gt;를 반환한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4. &lt;/span&gt;&lt;span&gt;뷰 &lt;/span&gt;&lt;span&gt;- InternalResourceView &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;InternalResourceView &lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;처럼 포워드 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;forward() &lt;/span&gt;&lt;span&gt;를 호출해서 처리할 수 있는 경우에 사용한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;5. view.render() &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;view.render() &lt;/span&gt;&lt;span&gt;가 호출되고 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;InternalResourceView &lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;forward() &lt;/span&gt;&lt;span&gt;를 사용해서 &lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;를 실행한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;참고&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;InternalResourceViewResolver &lt;/span&gt;&lt;span&gt;는 만약 &lt;/span&gt;&lt;span&gt;JSTL &lt;/span&gt;&lt;span&gt;라이브러리가 있으면 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;InternalResourceView &lt;/span&gt;&lt;span&gt;를 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;상속받은 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;JstlView &lt;/span&gt;&lt;span&gt;를 반환한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;JstlView &lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span&gt;JSTL &lt;/span&gt;&lt;span&gt;태그 사용시 약간의 부가 기능이 추가된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;참고&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span&gt;다른 뷰는 실제 뷰를 렌더링하지만&lt;/span&gt;&lt;span&gt;, JSP&lt;/span&gt;&lt;span&gt;의 경우 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;forward() &lt;/span&gt;&lt;span&gt;통해서 해당 &lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;로 이동&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;실행&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;해야 렌더링이 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;된다&lt;/span&gt;&lt;span&gt;. JSP&lt;/span&gt;&lt;span&gt;를 제외한 나머지 뷰 템플릿들은 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;forward() &lt;/span&gt;&lt;span&gt;과정 없이 바로 렌더링 된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;참고&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;span&gt;Thymeleaf &lt;/span&gt;&lt;span&gt;뷰 템플릿을 사용하면 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;ThymeleafViewResolver &lt;/span&gt;&lt;span&gt;를 등록해야 한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;최근에는 라이브러리만 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추가하면 스프링 부트가 이런 작업도 모두 자동화해준다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Spring/mvc</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/56</guid>
      <comments>https://zeroone.tistory.com/56#entry56comment</comments>
      <pubDate>Tue, 26 Jul 2022 05:52:59 +0900</pubDate>
    </item>
    <item>
      <title>MVC 프레임워크 만들기</title>
      <link>https://zeroone.tistory.com/55</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;프론트 컨트롤러 패턴 소개 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;1232&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKRnn8/btrHoOSr3bS/EETRMo9wkM4DPB2nOiAqGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKRnn8/btrHoOSr3bS/EETRMo9wkM4DPB2nOiAqGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKRnn8/btrHoOSr3bS/EETRMo9wkM4DPB2nOiAqGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKRnn8%2FbtrHoOSr3bS%2FEETRMo9wkM4DPB2nOiAqGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;540&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;1232&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FrontController 패턴 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프론트 컨트롤러 서블릿 하나로 클라이언트의 요청을 받음&lt;/li&gt;
&lt;li&gt;프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아서 호출&lt;/li&gt;
&lt;li&gt;입구를 하나로!&lt;/li&gt;
&lt;li&gt;공통 처리 가능&lt;/li&gt;
&lt;li&gt;프론트 컨트롤러를 제외한 나머지 컨트롤러는 서블릿을 사용하지 않아도 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;스프링 웹 &lt;/span&gt;&lt;span&gt;MVC&lt;/span&gt;&lt;span&gt;와 프론트 컨트롤러&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;스프링 웹 &lt;/span&gt;&lt;span&gt;MVC&lt;/span&gt;&lt;span&gt;의 핵심도 바로 &lt;/span&gt;&lt;span&gt;FrontController&lt;br /&gt;&lt;/span&gt;&lt;span&gt;스프링 웹 &lt;/span&gt;&lt;span&gt;MVC&lt;/span&gt;&lt;span&gt;의 &lt;/span&gt;&lt;span&gt;DispatcherServlet&lt;/span&gt;&lt;span&gt;이 &lt;/span&gt;&lt;span&gt;FrontController &lt;/span&gt;&lt;span&gt;패턴으로 구현되어 있음 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;1. 프론트 컨트롤러 도입 &lt;/span&gt;&lt;span&gt;- v1 &lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프론트 컨트롤러를 단계적으로 도입해보자.&lt;/li&gt;
&lt;li&gt;이번 목표는 기존 코드를 최대한 유지하면서, 프론트 컨트롤러를 도입하는 것이다.&lt;/li&gt;
&lt;li&gt;먼저 구조를 맞추어두고 점진적으로 리펙터링 해보자.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3LauR/btrHthee2ar/VsxOphnj0DZqNzlA4skf3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3LauR/btrHthee2ar/VsxOphnj0DZqNzlA4skf3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3LauR/btrHthee2ar/VsxOphnj0DZqNzlA4skf3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3LauR%2FbtrHthee2ar%2FVsxOphnj0DZqNzlA4skf3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;215&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;View &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;분리 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;- v2&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;모든 컨트롤러에서 뷰로 이동하는 부분에 중복이 있고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;깔끔하지 않다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657955726039&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String viewPath = &quot;/WEB-INF/views/new-form.jsp&quot;;
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 부분을 깔끔하게 분리하기 위해 별도로 뷰를 처리하는 객체(MyView)를 만들자&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DeYn4/btrHp2o7ZmO/1IAgffTgM5wm7a4TvdWQfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DeYn4/btrHp2o7ZmO/1IAgffTgM5wm7a4TvdWQfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DeYn4/btrHp2o7ZmO/1IAgffTgM5wm7a4TvdWQfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDeYn4%2FbtrHp2o7ZmO%2F1IAgffTgM5wm7a4TvdWQfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;254&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;3. Model &lt;/span&gt;&lt;span&gt;추가 &lt;/span&gt;&lt;span&gt;- v3 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;서블릿 종속성 제거&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컨트롤러 입장에서 &lt;/span&gt;&lt;span&gt;HttpServletRequest, HttpServletResponse&lt;/span&gt;&lt;span&gt;이 꼭 필요할까&lt;/span&gt;&lt;span&gt;?&lt;br /&gt;&lt;/span&gt;&lt;span&gt;요청 파라미터 정보는 자바의 &lt;/span&gt;&lt;span&gt;Map&lt;/span&gt;&lt;span&gt;으로 대신 넘기도록 하면 지금 구조에서는 컨트롤러가 서블릿 기술을 몰라도 동작할 수 있다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;그리고 &lt;/span&gt;&lt;span&gt;request &lt;/span&gt;&lt;span&gt;객체를 &lt;/span&gt;&lt;span&gt;Model&lt;/span&gt;&lt;span&gt;로 사용하는 대신에 별도의 &lt;/span&gt;&lt;span&gt;Model &lt;/span&gt;&lt;span&gt;객체를 만들어서 반환하면 된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;우리가 구현하는 컨트롤러가 서블릿 기술을 전혀 사용하지 않도록 변경해보자&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;이렇게 하면 구현 코드도 매우 단순해지고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;테스트 코드 작성이 쉽다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;뷰 이름 중복 제거&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컨트롤러에서 지정하는 뷰 이름에 중복이 있는 것을 확인할 수 있다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;컨트롤러는 &lt;/span&gt;&lt;span&gt;뷰의 논리 이름&lt;/span&gt;&lt;span&gt;을 반환하고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록 단순화 하자&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;이렇게 해두면 향후 뷰의 폴더 위치가 함께 이동해도 프론트 컨트롤러만 고치면 된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/WEB-INF/views/new-form.jsp -&amp;gt; new-form&lt;/li&gt;
&lt;li&gt;/WEB-INF/views/save-result.jsp -&amp;gt; save-result&lt;/li&gt;
&lt;li&gt;/WEB-INF/views/members.jsp -&amp;gt; members&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AtMCG/btrHpeDkJH6/348lAhtUr6jiJePW8SV3WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AtMCG/btrHpeDkJH6/348lAhtUr6jiJePW8SV3WK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AtMCG/btrHpeDkJH6/348lAhtUr6jiJePW8SV3WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAtMCG%2FbtrHpeDkJH6%2F348lAhtUr6jiJePW8SV3WK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;239&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;544&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;ModelView&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지 컨트롤러에서 서블릿에 종속적인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HttpServletRequest&lt;/span&gt;&lt;span&gt;를 사용했다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Model&lt;/span&gt;&lt;span&gt;도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;request.setAttribute()&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;를 통해 데이터를 저장하고 뷰에 전달했다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;서블릿의 종속성을 제거하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Model&lt;/span&gt;&lt;span&gt;을 직접 만들고&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;추가로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;View&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;이름까지 전달하는 객체를 만들어보자&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;이번 버전에서는 컨트롤러에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HttpServletRequest&lt;/span&gt;&lt;span&gt;를 사용할 수 없다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;따라서 직접&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;request.setAttribute()&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;를 호출할 수 도 없다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;따라서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Model&lt;/span&gt;&lt;span&gt;이 별도로 필요하다&lt;/span&gt;&lt;span&gt;.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;뷰 리졸버 &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;MyView view = viewResolver(viewName)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컨트롤러가 반환한 논리 뷰 이름을 실제 물리 뷰 경로로 변경한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;그리고 실제 물리 경로가 있는 &lt;/span&gt;&lt;span&gt;MyView &lt;/span&gt;&lt;span&gt;객체를 반환한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;논리 뷰 이름&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;members&lt;br /&gt;&lt;/span&gt;&lt;span&gt;물리 뷰 경로&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;/WEB-INF/views/members.jsp &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;cos&quot;&gt;&lt;code&gt;view.render(mv.getModel(), request, response)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;뷰 객체를 통해서 &lt;/span&gt;&lt;span&gt;HTML &lt;/span&gt;&lt;span&gt;화면을 렌더링 한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;뷰 객체의 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;render() &lt;/span&gt;&lt;span&gt;는 모델 정보도 함께 받는다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;JSP&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;request.getAttribute() &lt;/span&gt;&lt;span&gt;로 데이터를 조회하기 때문에&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;모델의 데이터를 꺼내서 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;request.setAttribute() &lt;/span&gt;&lt;span&gt;로 담아둔다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;JSP&lt;/span&gt;&lt;span&gt;로 포워드 해서 &lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;를 렌더링 한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;4. 단순하고 실용적인 컨트롤러 &lt;/span&gt;&lt;span&gt;- v4 &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;앞서 만든 &lt;/span&gt;&lt;span&gt;v3 &lt;/span&gt;&lt;span&gt;컨트롤러는 서블릿 종속성을 제거하고 뷰 경로의 중복을 제거하는 등&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;잘 설계된 컨트롤러이다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;그런데 실제 컨트톨러 인터페이스를 구현하는 개발자 입장에서 보면&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;항상 &lt;/span&gt;&lt;span&gt;ModelView &lt;/span&gt;&lt;span&gt;객체를 생성하고 반환해야 하는 부분이 조금은 번거롭다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;좋은 프레임워크는 아키텍처도 중요하지만&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;그와 더불어 실제 개발하는 개발자가 단순하고 편리하게 사용할 수 있어야 한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;소위 실용성이 있어야 한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번에는 &lt;/span&gt;&lt;span&gt;v3&lt;/span&gt;&lt;span&gt;를 조금 변경해서 실제 구현하는 개발자들이 매우 편리하게 개발할 수 있는 &lt;/span&gt;&lt;span&gt;v4 &lt;/span&gt;&lt;span&gt;버전을 개발해보자&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;FrontControllerServletV4 &lt;/span&gt;&lt;span&gt;는 사실 이전 버전과 거의 동일하다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;모델 객체 전달&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;Map&amp;lt;String, Object&amp;gt; model = new HashMap&amp;lt;&amp;gt;(); //&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;추가&lt;br /&gt;&lt;/span&gt;&lt;span&gt;모델 객체를 프론트 컨트롤러에서 생성해서 넘겨준다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;컨트롤러에서 모델 객체에 값을 담으면 여기에 그대로 담겨있게 된다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;뷰의 논리 이름을 직접 반환 (ModelView -&amp;gt; String)&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;  String viewName = controller.process(paramMap, model);
  MyView view = viewResolver(viewName);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컨트롤로가 직접 뷰의 논리 이름을 반환하므로 이 값을 사용해서 실제 물리 뷰를 찾을 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;5. 유연한 컨트롤러&lt;/span&gt;&lt;span&gt;&amp;nbsp;- v5&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 어떤 개발자는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;ControllerV3 &lt;/span&gt;&lt;span&gt;방식으로 개발하고 싶고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;어떤 개발자는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;ControllerV4 &lt;/span&gt;&lt;span&gt;방식으로 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;개발하고 싶다면 어떻게 해야할까&lt;/span&gt;&lt;span&gt;? &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public interface ControllerV3 {
    ModelView process(Map&amp;lt;String, String&amp;gt; paramMap);
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public interface ControllerV4 {
        String process(Map&amp;lt;String, String&amp;gt; paramMap, Map&amp;lt;String, Object&amp;gt; model);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;어댑터 패턴&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지 우리가 개발한 프론트 컨트롤러는 한가지 방식의 컨트롤러 인터페이스만 사용할 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;ControllerV3 &lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;ControllerV4 &lt;/span&gt;&lt;span&gt;는 완전히 다른 인터페이스이다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;따라서 호환이 불가능하다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;마치 &lt;/span&gt;&lt;span&gt;v3&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span&gt;110v&lt;/span&gt;&lt;span&gt;이고&lt;/span&gt;&lt;span&gt;, v4&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span&gt;220v &lt;/span&gt;&lt;span&gt;전기 콘센트 같은 것이다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;이럴 때 사용하는 것이 바로 어댑터이다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;어댑터 패턴을 사용해서 프론트 컨트롤러가 다양한 방식의 컨트롤러를 처리할 수 있도록 변경해보자&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwx3vg/btrHrNShBRj/vUI5kEYVOKJv1fDTKBWIw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwx3vg/btrHrNShBRj/vUI5kEYVOKJv1fDTKBWIw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwx3vg/btrHrNShBRj/vUI5kEYVOKJv1fDTKBWIw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbwx3vg%2FbtrHrNShBRj%2FvUI5kEYVOKJv1fDTKBWIw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;183&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;핸들러 어댑터&lt;/span&gt;&lt;/b&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;중간에 어댑터 역할을 하는 어댑터가 추가되었는데 이름이 핸들러 어댑터이다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;여기서 어댑터 역할을 해주는 덕분에 다양한 종류의 컨트롤러를 호출할 수 있다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;핸들러&lt;/span&gt;&lt;/b&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;컨트롤러의 이름을 더 넓은 범위인 핸들러로 변경했다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;그 이유는 이제 어댑터가 있기 때문에 꼭 컨트롤러의 개념 뿐만 아니라 어떠한 것이든 해당하는 종류의 어댑터만 있으면 다 처리할 수 있기 때문이다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;컨트롤러&lt;/span&gt;&lt;span&gt;(Controller) -&amp;gt; &lt;/span&gt;&lt;span&gt;핸들러&lt;/span&gt;&lt;span&gt;(Handler)&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이전에는 컨트롤러를 직접 매핑해서 사용했다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;그런데 이제는 어댑터를 사용하기 때문에&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;컨트롤러 뿐만 아니라 어댑터가 지원하기만 하면&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;어떤 것이라도 &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt;에 매핑해서 사용할 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;그래서 이름을 컨트롤러에서 더 넒은 범위의 핸들러로 변경했다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Spring/mvc</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/55</guid>
      <comments>https://zeroone.tistory.com/55#entry55comment</comments>
      <pubDate>Sat, 16 Jul 2022 16:39:19 +0900</pubDate>
    </item>
    <item>
      <title>서블릿, JSP, MVC 패턴</title>
      <link>https://zeroone.tistory.com/54</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;1. 서블릿으로 회원 관리 웹 애플리케이션 만들기&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;MemberFormServlet&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;은 단순하게 회원 정보를 입력할 수 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML Form&lt;/span&gt;&lt;span&gt;을 만들어서 응답한다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;자바 코드로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;/span&gt;&lt;span&gt;을 제공해야 하므로 쉽지 않은 작업이다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;템플릿 엔진으로&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;지금까지 서블릿과 자바 코드만으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;/span&gt;&lt;span&gt;을 만들어보았다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;서블릿 덕분에 동적으로 원하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;/span&gt;&lt;span&gt;을 마음껏 만들 수 있다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;정적인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;문서라면 화면이 계속 달라지는 회원의 저장 결과라던가&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;회원 목록 같은 동적인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;/span&gt;&lt;span&gt;을 만드는 일은 불가능 할 것이다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;그런데&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;코드에서 보듯이 이것은 매우 복잡하고 비효율 적이다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;자바 코드로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;/span&gt;&lt;span&gt;을 만들어 내는 것 보다 차라리&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;문서에 동적으로 변경해야 하는 부분만 자바 코드를 넣을 수 있다면 더 편리할 것이다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;이것이 바로 템플릿 엔진이 나온 이유이다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;템플릿 엔진을 사용하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;문서에서 필요한 곳만 코드를 적용해서 동적으로 변경할 수 있다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;템플릿 엔진에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSP, Thymeleaf, Freemarker, Velocity&lt;/span&gt;&lt;span&gt;등이 있다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;다음 시간에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;로 동일한 작업을 진행해보자&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;2. JSP&lt;/span&gt;&lt;span&gt;로 회원 관리 웹 애플리케이션 만들기&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;서블릿과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;의 한계&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서블릿으로 개발할 때는 뷰&lt;/span&gt;&lt;span&gt;(View)&lt;/span&gt;&lt;span&gt;화면을 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;/span&gt;&lt;span&gt;을 만드는 작업이 자바 코드에 섞여서 지저분하고 복잡했다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;JSP&lt;/span&gt;&lt;span&gt;를 사용한 덕분에 뷰를 생성하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;작업을 깔끔하게 가져가고&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;중간중간 동적으로 변경이 필요한 부분에만 자바 코드를 적용했다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;그런데 이렇게 해도 해결되지 않는 몇가지 고민이 남는다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;회원 저장&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;를 보자&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;코드의 상위 절반은 회원을 저장하기 위한 비즈니스 로직이고&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;나머지 하위 절반만 결과를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;/span&gt;&lt;span&gt;로 보여주기 위한 뷰 영역이다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;회원 목록의 경우에도 마찬가지다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;코드를 잘 보면&lt;/span&gt;&lt;span&gt;, JAVA&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;코드&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;데이터를 조회하는 리포지토리 등등 다양한 코드가 모두&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;에 노출되어 있다&lt;/span&gt;&lt;span&gt;. JSP&lt;/span&gt;&lt;span&gt;가 너무 많은 역할을 한다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;이렇게 작은 프로젝트도 벌써 머리가 아파오는데&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;수백 수천줄이 넘어가는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;를 떠올려보면 정말 지옥과 같을 것이다&lt;/span&gt;&lt;span&gt;. (&lt;/span&gt;&lt;span&gt;유지보수 지옥 썰&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;3. MVC&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;패턴의 등장&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비즈니스 로직은 서블릿 처럼 다른곳에서 처리하고&lt;/span&gt;&lt;span&gt;, JSP&lt;/span&gt;&lt;span&gt;는 목적에 맞게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;/span&gt;&lt;span&gt;로 화면&lt;/span&gt;&lt;span&gt;(View)&lt;/span&gt;&lt;span&gt;을 그리는 일에 집중하도록 하자&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;과거 개발자들도 모두 비슷한 고민이 있었고&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;그래서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;MVC&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;패턴이 등장했다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;우리도 직접&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;MVC&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;패턴을 적용해서 프로젝트를 리팩터링 해보자&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;MVC&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;패턴&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;개요&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;너무 많은 역할&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;하나의 서블릿이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSP&lt;/span&gt;&lt;span&gt;만으로 비즈니스 로직과 뷰 렌더링까지 모두 처리하게 되면&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;너무 많은 역할을 하게되고&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;결과적으로 유지보수가 어려워진다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;비즈니스 로직을 호출하는 부분에 변경이 발생해도 해당 코드를 손대야 하고&lt;/span&gt;&lt;span&gt;, UI&lt;/span&gt;&lt;span&gt;를 변경할 일이 있어도 비즈니스 로직이 함께 있는 해당 파일을 수정해야 한다&lt;/span&gt;&lt;span&gt;. HTML&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;코드 하나 수정해야 하는데&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;수백줄의 자바 코드가 함께 있다고 상상해보라&lt;/span&gt;&lt;span&gt;!&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;또는 비즈니스 로직을 하나 수정해야 하는데 수백 수천줄의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;HTML&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;코드가 함께 있다고 상상해보라&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;변경의 라이프 사이클&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;사실 이게 정말 중요한데&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;진짜 문제는 둘 사이에 변경의 라이프 사이클이 다르다는 점이다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;예를 들어서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;UI&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;를 일부 수정하는 일과 비즈니스 로직을 수정하는 일은 각각 다르게 발생할 가능성이 매우 높고 대부분 서로에게 영향을 주지 않는다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;이렇게 변경의 라이프 사이클이 다른 부분을 하나의 코드로 관리하는 것은 유지보수하기 좋지 않다&lt;/span&gt;&lt;span&gt;. (&lt;/span&gt;&lt;span&gt;물론&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;UI&lt;/span&gt;&lt;span&gt;가 많이 변하면 함께 변경될 가능성도 있다&lt;/span&gt;&lt;span&gt;.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;기능 특화&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;JSP&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;같은 뷰 템플릿은 화면을 렌더링 하는데 최적화 되어 있기 때문에 이 부분의 업무만 담당하는 것이 가장 효과적이다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Model View Controller&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;MVC&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;패턴은 지금까지 학습한 것 처럼 하나의 서블릿이나&lt;/span&gt;&lt;span&gt;, JSP&lt;/span&gt;&lt;span&gt;로 처리하던 것을 컨트롤러&lt;/span&gt;&lt;span&gt;(Controller)&lt;/span&gt;&lt;span&gt;와 뷰&lt;/span&gt;&lt;span&gt;(View)&lt;/span&gt;&lt;span&gt;라는 영역으로 서로 역할을 나눈 것을 말한다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;웹 애플리케이션은 보통 이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;MVC&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;패턴을 사용한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨트롤러: HTTP&amp;nbsp;요청을 받아서 파라미터를 검증하고,&amp;nbsp;비즈니스 로직을 실행한다.&amp;nbsp;그리고 뷰에 전달할 결과 데이터를 조회해서 모델에 담는다.&lt;/li&gt;
&lt;li&gt;모델&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;뷰에 출력할 데이터를 담아둔다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;뷰가 필요한 데이터를 모두 모델에 담아서 전달해주는 덕분에 뷰는 비즈니스 로직이나 데이터 접근을 몰라도 되고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;화면을 렌더링 하는 일에 집중할 수 있다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;뷰&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;:&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;모델에 담겨있는 데이터를 사용해서 화면을 그리는 일에 집중한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;여기서는&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;HTML&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;을 생성하는 부분을 말한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;lt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;참고&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컨트롤러에 비즈니스 로직을 둘 수도 있지만&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;이렇게 되면 컨트롤러가 너무 많은 역할을 담당한다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;그래서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;일반적으로 비즈니스 로직은 서비스&lt;/span&gt;&lt;span&gt;(Service)&lt;/span&gt;&lt;span&gt;라는 계층을 별도로 만들어서 처리한다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;그리고 컨트롤러는 비즈니스 로직이 있는 서비스를 호출하는 역할을 담당한다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;참고로 비즈니스 로직을 변경하면 비즈니스 로직을 호출하는 컨트롤러의 코드도 변경될 수 있다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;앞에서는 이해를 돕기 위해 비즈니스 로직을 호출한다는 표현 보다는&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;비즈니스 로직이라 설명했다.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1zSI7/btrHpyuI74B/5G3IDNfCSfDvm3OLwLdkZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1zSI7/btrHpyuI74B/5G3IDNfCSfDvm3OLwLdkZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1zSI7/btrHpyuI74B/5G3IDNfCSfDvm3OLwLdkZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1zSI7%2FbtrHpyuI74B%2F5G3IDNfCSfDvm3OLwLdkZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;211&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;742&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qFgEe/btrHoN0fVh4/lgkvK9qnlOWRdkOUYLoZkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qFgEe/btrHoN0fVh4/lgkvK9qnlOWRdkOUYLoZkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qFgEe/btrHoN0fVh4/lgkvK9qnlOWRdkOUYLoZkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqFgEe%2FbtrHoN0fVh4%2FlgkvK9qnlOWRdkOUYLoZkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;325&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;742&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SfLnQ/btrHqD9VEhs/zeT4eqCFw3ZxGb7sTeKmVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SfLnQ/btrHqD9VEhs/zeT4eqCFw3ZxGb7sTeKmVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SfLnQ/btrHqD9VEhs/zeT4eqCFw3ZxGb7sTeKmVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSfLnQ%2FbtrHqD9VEhs%2FzeT4eqCFw3ZxGb7sTeKmVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;218&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;MVC &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;패턴&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;-&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;한계&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;MVC&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;패턴을 적용한 덕분에 컨트롤러의 역할과 뷰를 렌더링 하는 역할을 명확하게 구분할 수 있다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;특히 뷰는 화면을 그리는 역할에 충실한 덕분에&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;코드가 깔끔하고 직관적이다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;단순하게 모델에서 필요한 데이터를 꺼내고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;화면을 만들면 된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;그런데 컨트롤러는 딱 봐도 중복이 많고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;필요하지 않는 코드들도 많이 보인다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;MVC&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;컨트롤러의 단점&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;1. 포워드 중복&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;View&lt;/span&gt;&lt;span&gt;로 이동하는 코드가 항상 중복 호출되어야 한다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;물론 이 부분을 메서드로 공통화해도 되지만&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;해당 메서드도 항상 직접 호출해야 한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;vbscript&quot;&gt;&lt;code&gt;  RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
  dispatcher.forward(request, response);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;2. ViewPath&lt;/span&gt;&lt;span&gt;에 중복&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657953715764&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String viewPath = &quot;/WEB-INF/views/new-form.jsp&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;prefix:&amp;nbsp;/WEB-INF/views/&lt;/li&gt;
&lt;li&gt;suffix:&amp;nbsp;.jsp&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 만약&amp;nbsp;jsp가 아닌&amp;nbsp;thymeleaf&amp;nbsp;같은 다른 뷰로 변경한다면 전체 코드를 다 변경해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;3. 사용하지 않는 코드&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다음 코드를 사용할 때도 있고&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;사용하지 않을 때도 있다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;특히&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt;는 현재 코드에서 사용되지 않는다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;vbscript&quot;&gt;&lt;code&gt;  HttpServletRequest request, HttpServletResponse response
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그리고 이런&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;HttpServletRequest&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;HttpServletResponse&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;를 사용하는 코드는 테스트 케이스를 작성하기도 어렵다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;4. 공통 처리가 어렵다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;기능이 복잡해질 수 록 컨트롤러에서 공통으로 처리해야 하는 부분이 점점 더 많이 증가할 것이다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;단순히 공통 기능을 메서드로 뽑으면 될 것 같지만&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;결과적으로 해당 메서드를 항상 호출해야 하고&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;실수로 호출하지 않으면 문제가 될 것이다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;그리고 호출하는 것 자체도 중복이다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;&lt;br /&gt;5. 정리하면 공통 처리가 어렵다는 문제가 있다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;span&gt;이 문제를 해결하려면 컨트롤러 호출 전에 먼저 공통 기능을 처리해야 한다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;소위&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;수문장 역할&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 하는 기능이 필요하다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span&gt;프론트 컨트롤러&lt;/span&gt;&lt;span&gt;(Front Controller)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;패턴&lt;/span&gt;&lt;/b&gt;&lt;span&gt;을 도입하면 이런 문제를 깔끔하게 해결할 수 있다&lt;/span&gt;&lt;span&gt;. (&lt;/span&gt;&lt;span&gt;입구를 하나로&lt;/span&gt;&lt;span&gt;!)&lt;br /&gt;&lt;/span&gt;&lt;span&gt;스프링&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;MVC&lt;/span&gt;&lt;span&gt;의 핵심도 바로 이 프론트 컨트롤러에 있다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Spring/mvc</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/54</guid>
      <comments>https://zeroone.tistory.com/54#entry54comment</comments>
      <pubDate>Sat, 16 Jul 2022 15:44:14 +0900</pubDate>
    </item>
    <item>
      <title>서블릿</title>
      <link>https://zeroone.tistory.com/53</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;스프링부트 서블릿 등록, 사용&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@ServletComponentScan&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;&lt;/span&gt;&lt;span&gt;스프링 부트는 서블릿을 직접 등록해서 사용할 수 있도록 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@ServletComponentScan &lt;/span&gt;&lt;span&gt;을 지원한다&lt;/span&gt;&lt;span&gt;. &lt;br /&gt;&lt;/span&gt;&lt;span&gt;다음과 &lt;/span&gt;&lt;span&gt;같이 추가하자&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@WebServlet&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;서블릿 애노테이션 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;name: &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;서블릿 이름 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;urlPatterns: URL &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;매핑&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;hello.servlet.ServletApplication&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1657947766979&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.servlet;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan //서블릿 자동 등록 
@SpringBootApplication
public class ServletApplication {
     public static void main(String[] args) {
        SpringApplication.run(ServletApplication.class, args);
	} 
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;hello.servlet.basic.HelloServlet &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1657947812201&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.servlet.basic;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = &quot;helloServlet&quot;, urlPatterns = &quot;/hello&quot;)
public class HelloServlet extends HttpServlet {
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println(&quot;HelloServlet.service&quot;);
        System.out.println(&quot;request = &quot; + request);
        System.out.println(&quot;response = &quot; + response);
        String username = request.getParameter(&quot;username&quot;);
        System.out.println(&quot;username = &quot; + username);
        response.setContentType(&quot;text/plain&quot;);
        response.setCharacterEncoding(&quot;utf-8&quot;);
		response.getWriter().write(&quot;hello &quot; + username);
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서블릿 컨테이너 동작방식&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuL1Qu/btrHrOcugfy/NH7k99talfJj2huKqk1cik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuL1Qu/btrHrOcugfy/NH7k99talfJj2huKqk1cik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuL1Qu/btrHrOcugfy/NH7k99talfJj2huKqk1cik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuL1Qu%2FbtrHrOcugfy%2FNH7k99talfJj2huKqk1cik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;225&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vo9iu/btrHoHe6kIj/mI3evSY4ARKcLj1hr04NCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vo9iu/btrHoHe6kIj/mI3evSY4ARKcLj1hr04NCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vo9iu/btrHoHe6kIj/mI3evSY4ARKcLj1hr04NCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fvo9iu%2FbtrHoHe6kIj%2FmI3evSY4ARKcLj1hr04NCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;361&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;HttpServletRequest&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HttpServletRequest 역할&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HTTP &lt;/span&gt;&lt;span&gt;요청 메시지를 개발자가 직접 파싱해서 사용해도 되지만&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;매우 불편할 것이다&lt;/span&gt;&lt;span&gt;. &lt;br /&gt;&lt;/span&gt;&lt;span&gt;서블릿은 개발자가 &lt;/span&gt;&lt;span&gt;HTTP &lt;/span&gt;&lt;span&gt;요청 메시지를 편리하게 사용할 수 있도록 개발자 대신에 &lt;/span&gt;&lt;span&gt;HTTP &lt;/span&gt;&lt;span&gt;요청 메시지를 파싱한다&lt;/span&gt;&lt;span&gt;. &lt;br /&gt;&lt;/span&gt;&lt;span&gt;그리고 그 결과를 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;HttpServletRequest &lt;/span&gt;&lt;span&gt;객체에 담아서 제공한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HttpServletRequest&lt;/span&gt;&lt;span&gt;를 사용하면 다음과 같은 &lt;/span&gt;&lt;span&gt;HTTP &lt;/span&gt;&lt;span&gt;요청 메시지를 편리하게 조회할 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;HTTP &lt;/span&gt;&lt;span&gt;요청 메시지 &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;POST /save HTTP/1.1
Host: localhost:8080
Content-Type: application/x-www-form-urlencoded

username=kim&amp;amp;age=20&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HttpServletRequest 개요&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;START LINE &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 메소드&lt;/li&gt;
&lt;li&gt;URL&lt;/li&gt;
&lt;li&gt;쿼리 스트링&lt;/li&gt;
&lt;li&gt;스키마, 프로토콜 헤더&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;헤더&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;헤더 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;바디 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;form 파라미터 형식 조회&lt;/li&gt;
&lt;li&gt;message body 데이터 직접 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;HttpServletRequest &lt;/span&gt;&lt;span&gt;객체는 추가로 여러가지 부가기능도 함께 제공한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;임시 저장소 기능 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해당 HTTP 요청이 시작부터 끝날 때 까지 유지되는 임시 저장소 기능&lt;br /&gt;- 저장&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;request.setAttribute(name, value)&lt;br /&gt;&lt;/span&gt;- 조회&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;request.getAttribute(name)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;세션 관리 기능 &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;request.getSession(create: true)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;HttpServletResponse&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HttpServletResponse 역할&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 응답 메시지 생성&lt;/li&gt;
&lt;li&gt;HTTP 응답코드 지정 헤더 생성&lt;/li&gt;
&lt;li&gt;바디 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;편의 기능 제공&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Content-Type, 쿠키, Redirect&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>Spring/mvc</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/53</guid>
      <comments>https://zeroone.tistory.com/53#entry53comment</comments>
      <pubDate>Sat, 16 Jul 2022 15:31:16 +0900</pubDate>
    </item>
    <item>
      <title>HTML, HTTP API, CSR, SSR</title>
      <link>https://zeroone.tistory.com/52</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;정적 리소스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고정된 HTML 파일, CSS, JS, 이미지, 영상 등을 제공&lt;/li&gt;
&lt;li&gt;주로 웹 브라우저&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;동적 리소스&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;1. HTML &lt;/span&gt;&lt;span&gt;페이지&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적으로 필요한 HTML 파일을 생성해서 전달&lt;/li&gt;
&lt;li&gt;웹 브라우저: HTML 해석&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;2. HTTP API&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML이 아니라 데이터를 전달&lt;/li&gt;
&lt;li&gt;주로 JSON 형식 사용&lt;/li&gt;
&lt;li&gt;다양한 시스템에서 호출&lt;/li&gt;
&lt;li&gt;데이터만 주고 받음, UI 화면이 필요하면, 클라이언트가 별도 처리&lt;/li&gt;
&lt;li&gt;주로 JSON 형태로 데이터 통신&lt;/li&gt;
&lt;li&gt;UI 클라이언트 접점&lt;/li&gt;
&lt;li&gt;앱 클라이언트(아이폰, 안드로이드, PC 앱)&lt;/li&gt;
&lt;li&gt;웹 브라우저에서 자바스크립트를 통한 HTTP API 호출&lt;/li&gt;
&lt;li&gt;React, Vue.js 같은 웹 클라이언트&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;3. 서버 &lt;/span&gt;&lt;span&gt;to &lt;/span&gt;&lt;span&gt;서버&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주문 서버 -&amp;gt; 결제 서버&lt;/li&gt;
&lt;li&gt;기업간 데이터 통신&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;서버사이드 렌더링&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;클라이언트 사이드 렌더링 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;SSR - &lt;/span&gt;&lt;span&gt;서버 사이드 렌더링 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 최종 결과를 서버에서 만들어서 웹 브라우저에 전달 주로 정적인 화면에 사용&lt;/li&gt;
&lt;li&gt;관련기술: JSP, 타임리프 -&amp;gt; 백엔드 개발자&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bOcaT1/btrGg0lCGtb/20y27Xtiklt2dbYM8G5zv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bOcaT1/btrGg0lCGtb/20y27Xtiklt2dbYM8G5zv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bOcaT1/btrGg0lCGtb/20y27Xtiklt2dbYM8G5zv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbOcaT1%2FbtrGg0lCGtb%2F20y27Xtiklt2dbYM8G5zv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;225&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;CSR - &lt;/span&gt;&lt;span&gt;클라이언트 사이드 렌더링 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML 결과를 자바스크립트를 사용해 웹 브라우저에서 동적으로 생성해서 적용&lt;/li&gt;
&lt;li&gt;주로 동적인 화면에 사용, 웹 환경을 마치 앱 처럼 필요한 부분부분 변경할 수 있음&lt;/li&gt;
&lt;li&gt;예) 구글 지도, Gmail, 구글 캘린더&lt;/li&gt;
&lt;li&gt;관련기술&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;: React, Vue.js &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;-&amp;gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;웹 프론트엔드 개발자&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Whcgi/btrGlgAUE2W/ovm8JCzkZykq8oAVbSQDe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Whcgi/btrGlgAUE2W/ovm8JCzkZykq8oAVbSQDe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Whcgi/btrGlgAUE2W/ovm8JCzkZykq8oAVbSQDe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWhcgi%2FbtrGlgAUE2W%2Fovm8JCzkZykq8oAVbSQDe0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;225&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;참고&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React, Vue.js를 CSR + SSR 동시에 지원하는 웹 프레임워크도 있음&lt;/li&gt;
&lt;li&gt;SSR을 사용하더라도, 자바스크립트를 사용해서 화면 일부를 동적으로 변경 가능 &lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Spring/mvc</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/52</guid>
      <comments>https://zeroone.tistory.com/52#entry52comment</comments>
      <pubDate>Sun, 3 Jul 2022 00:10:15 +0900</pubDate>
    </item>
    <item>
      <title>동시요청 - 멀티 스레드</title>
      <link>https://zeroone.tistory.com/51</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;쓰레드&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션 코드를 하나하나 순차적으로 실행하는 것은 쓰레드&lt;/li&gt;
&lt;li&gt;자바 메인 메서드를 처음 실행하면 main이라는 이름의 쓰레드가 실행&lt;/li&gt;
&lt;li&gt;쓰레드가 없다면 자바 애플리케이션 실행이 불가능&lt;/li&gt;
&lt;li&gt;쓰레드는 한번에 하나의 코드 라인만 수행&lt;/li&gt;
&lt;li&gt;동시 처리가 필요하면 쓰레드를 추가로 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 요청 - 쓰레드 하나 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다중 요청 - 쓰레드 하나 사용&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;나중에 들어온 요청이 대기하게 된다. 동시 요청 처리 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 마다 쓰레드 사용&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동시 요청을 처리할 수 있다.&lt;/li&gt;
&lt;li&gt;장점&lt;br /&gt;리소스(CPU, 메모리)가 허용할 때 까지 처리가능&lt;br /&gt;하나의 쓰레드가 지연 되어도&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;나머지 쓰레드는 정상 동작한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;단점&lt;br /&gt;쓰레드는 생성 비용은 매우 비싸다&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;고객의 요청이 올 때 마다 쓰레드를 생성하면&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;응답 속도가 늦어진다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;쓰레드는 컨텍스트 스위칭 비용이 발생한다&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;쓰레드 생성에 제한이 없다&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;고객 요청이 너무 많이 오면&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, CPU, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;메모리 임계점을 넘어서 서버가 죽을 수 있다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰레드 풀&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필요한 쓰레드를 쓰레드 풀에 보관하고 관리한다.&lt;/li&gt;
&lt;li&gt;특징&lt;br /&gt;쓰레드 풀에 생성 가능한 쓰레드의 최대치를 관리한다&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;. &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;톰캣은 최대 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;200&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;개 기본 설정 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;변경 가능&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;사용&lt;br /&gt;쓰레드가 필요하면&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이미 생성되어 있는 쓰레드를 쓰레드 풀에서 꺼내서 사용한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;사용을 종료하면 쓰레드 풀에 해당 쓰레드를 반납한다&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;최대 쓰레드가 모두 사용중이어서 쓰레드 풀에 쓰레드가 없으면&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;? &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;기다리는 요청은 거절하거나 특정 숫자만큼만 대기하도록 설정할 수 있다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;장점&lt;br /&gt;쓰레드가 미리 생성되어 있으므로&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;쓰레드를 생성하고 종료하는 비용&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;(CPU)&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이 절약되고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;응답 시간이 빠르다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;생성 가능한 쓰레드의 최대치가 있으므로 너무 많은 요청이 들어와도 기존 요청은 안전하게 처리할 수 있다&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실무 팁&lt;br /&gt;WAS&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;의 주요 튜닝 포인트는 최대 쓰레드&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;(max thread) &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;수이다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;br /&gt;&lt;/span&gt;이 값을 너무 낮게 설정하면&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;?&lt;br /&gt;&lt;/span&gt;동시 요청이 많으면&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;서버 리소스는 여유롭지만&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;클라이언트는 금방 응답 지연&lt;br /&gt;이 값을 너무 높게 설정하면&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;?&lt;br /&gt;&lt;/span&gt;동시 요청이 많으면&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, CPU, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;메모리 리소스 임계점 초과로 서버 다운 &lt;br /&gt;장애 발생시&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;?&lt;br /&gt;&lt;/span&gt;클라우드면 일단 서버부터 늘리고&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이후에 튜닝 클라우드가 아니면 열심히 튜닝&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;성능 테스트&lt;br /&gt;&lt;/span&gt;최대한 실제 서비스와 유사하게 성능, 테스트 시도 툴&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;아파치 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;ab, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;제이미터&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, nGrinder&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;멀티 쓰레드에 대한 부분은 &lt;/span&gt;&lt;span&gt;WAS&lt;/span&gt;&lt;span&gt;가 처리&lt;br /&gt;&lt;/span&gt;&lt;span&gt;개발자가 멀티 쓰레드 관련 코드를 신경쓰지 않아도 됨&lt;br /&gt;&lt;/span&gt;&lt;span&gt;개발자는 마치 &lt;/span&gt;&lt;span&gt;싱글 쓰레드 프로그래밍을 하듯이 편리하게 소스 코드를 개발 &lt;br /&gt;&lt;/span&gt;&lt;span&gt;멀티 쓰레드 환경이므로 싱글톤 객체&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;서블릿&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;스프링 빈&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;는 주의해서 사용 &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMfeBb/btrGgmWT5yl/fDJ5G3ZUK0tWc26H1S0CFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMfeBb/btrGgmWT5yl/fDJ5G3ZUK0tWc26H1S0CFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMfeBb/btrGgmWT5yl/fDJ5G3ZUK0tWc26H1S0CFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMfeBb%2FbtrGgmWT5yl%2FfDJ5G3ZUK0tWc26H1S0CFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;225&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cB7uDR/btrGlUK5Kay/AwAfs98f9PBkpXvHdzxuCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cB7uDR/btrGlUK5Kay/AwAfs98f9PBkpXvHdzxuCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cB7uDR/btrGlUK5Kay/AwAfs98f9PBkpXvHdzxuCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcB7uDR%2FbtrGlUK5Kay%2FAwAfs98f9PBkpXvHdzxuCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;225&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring/mvc</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/51</guid>
      <comments>https://zeroone.tistory.com/51#entry51comment</comments>
      <pubDate>Sat, 2 Jul 2022 22:55:37 +0900</pubDate>
    </item>
    <item>
      <title>서블릿, 서블릿 컨테이너</title>
      <link>https://zeroone.tistory.com/50</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;서블릿&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트의 요청을 처리하고, 그 결과를 반환하는 Servlet 클래스의 구현 규칙을 지킨 자바 웹 프로그래밍&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3upi5/btrD18L4247/HdpDV0v4YnBkZa0sEft1c1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3upi5/btrD18L4247/HdpDV0v4YnBkZa0sEft1c1/img.png&quot; data-alt=&quot;개발자가 비즈니스 로직에 집중할 수 있도록 소켓 연결등의 잡일을 지원한다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3upi5/btrD18L4247/HdpDV0v4YnBkZa0sEft1c1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3upi5%2FbtrD18L4247%2FHdpDV0v4YnBkZa0sEft1c1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;225&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개발자가 비즈니스 로직에 집중할 수 있도록 소켓 연결등의 잡일을 지원한다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1654407440569&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@WebServlet(name = &quot;helloServlet&quot;, urlPatterns = &quot;/hello&quot;) 
public class HelloServlet extends HttpServlet {
    @Override protected void service(HttpServletRequest request, HttpServletResponse response){ 
    	//애플리케이션 로직 
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;urlPatterns(&lt;b&gt;/hello&lt;/b&gt;)&lt;/span&gt;&lt;span&gt;의&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;URL&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;호출되면&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;서블릿&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;코드가&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;실행&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;HTTP &lt;/span&gt;&lt;span&gt;요청&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;정보를&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;편리하게&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;사용할&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;수&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;있는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HttpServletRequest&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;HTTP &lt;/span&gt;&lt;span&gt;응답&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;정보를&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;편리하게&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;제공할&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;수&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;있는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HttpServletResponse&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;개발자는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HTTP&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;스펙을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;매우&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;편리하게&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;사용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7KehJ/btrDYKrWBtB/HD97QGrF0Q5q5FEznXuUik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7KehJ/btrDYKrWBtB/HD97QGrF0Q5q5FEznXuUik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7KehJ/btrDYKrWBtB/HD97QGrF0Q5q5FEznXuUik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7KehJ%2FbtrDYKrWBtB%2FHD97QGrF0Q5q5FEznXuUik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;225&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 요청시&lt;/li&gt;
&lt;li&gt;WAS는 Request, Response 객체를 새로 만들어서 서블릿 객체 호출&lt;/li&gt;
&lt;li&gt;개발자는 Request 객체에서 HTTP 요청 정보를 편리하게 꺼내서 사용&lt;/li&gt;
&lt;li&gt;개발자는 Response 객체에 HTTP 응답 정보를 편리하게 입력&lt;/li&gt;
&lt;li&gt;WAS는 Response 객체에 담겨있는 내용으로 HTTP 응답 정보를 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;서블릿 컨테이너&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;톰캣처럼 서블릿을 지원하는 WAS를 서블릿 컨테이너라고 함&lt;/li&gt;
&lt;li&gt;서블릿 컨테이너는 서블릿 객체를 생성, 초기화, 호출, 종료하는 생명주기 관리&lt;/li&gt;
&lt;li&gt;서블릿 객체는 &lt;b&gt;싱글톤으로 관리&lt;/b&gt;&lt;br /&gt;- 고객의 요청이 올 때 마다 계속 객체를 생성하는 것은 비효율&lt;br /&gt;- 최초 로딩 시점에 서블릿 객체를 미리 만들어두고 재활용&lt;br /&gt;- 모든 고객 요청은 동일한 서블릿 객체 인스턴스에 접근&lt;br /&gt;- &lt;b&gt;공유 변수 사용 주의&lt;/b&gt;&lt;br /&gt;- 서블릿 컨테이너 종료시 함께 종료&lt;/li&gt;
&lt;li&gt;JSP도 서블릿으로 변환 되어서 사용&lt;/li&gt;
&lt;li&gt;동시 요청을 위한 멀티 쓰레드 처리 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Mb4Gy/btrD1gDCHfx/uhfQ9hR1SSy2g8Dh4ZbkcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Mb4Gy/btrD1gDCHfx/uhfQ9hR1SSy2g8Dh4ZbkcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Mb4Gy/btrD1gDCHfx/uhfQ9hR1SSy2g8Dh4ZbkcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMb4Gy%2FbtrD1gDCHfx%2FuhfQ9hR1SSy2g8Dh4ZbkcK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;225&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;890&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring/mvc</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/50</guid>
      <comments>https://zeroone.tistory.com/50#entry50comment</comments>
      <pubDate>Sun, 5 Jun 2022 14:48:32 +0900</pubDate>
    </item>
    <item>
      <title>웹 애플리케이션의 이해</title>
      <link>https://zeroone.tistory.com/49</link>
      <description>&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;웹 서버&lt;/span&gt;&lt;span&gt;(Web Server) &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 기반으로 동작&lt;/li&gt;
&lt;li&gt;정적 리소스 제공, 기타 부가기능&lt;/li&gt;
&lt;li&gt;정적(파일) HTML, CSS, JS, 이미지, 영상&lt;/li&gt;
&lt;li&gt;예) NGINX, APACHE&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;웹 애플리케이션 서버&lt;/span&gt;&lt;span&gt;(WAS - Web Application Server) &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 기반으로 동작&lt;/li&gt;
&lt;li&gt;웹 서버 기능 포함+ (정적 리소스 제공 가능)&lt;/li&gt;
&lt;li&gt;프로그램 코드를 실행해서 애플리케이션 로직 수행&lt;br /&gt;&amp;nbsp;- 동적 HTML, HTTP API(JSON)&lt;br /&gt;- 서블릿&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, JSP, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;스프링 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;MVC&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;예&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;톰캣&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;(Tomcat) Jetty, Undertow&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;웹 서버&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;웹 애플리케이션 서버&lt;/span&gt;&lt;span&gt;(WAS) &lt;/span&gt;&lt;span&gt;차이 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 서버는 정적 리소스(파일), WAS는 애플리케이션 로직 사실은 둘의 용어도 경계도 모호함&lt;/li&gt;
&lt;li&gt;웹 서버도 프로그램을 실행하는 기능을 포함하기도 함&lt;/li&gt;
&lt;li&gt;웹 애플리케이션 서버도 웹 서버의 기능을 제공함&lt;/li&gt;
&lt;li&gt;자바는 서블릿 컨테이너 기능을 제공하면 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;WAS&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;서블릿 없이 자바코드를 실행하는 서버 프레임워크도 있음 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;WAS&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;는 애플리케이션 코드를 실행하는데 더 특화&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;1. 웹 시스템 구성 &lt;/span&gt;&lt;span&gt;- WAS, DB &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WAS, DB 만으로 시스템 구성 가능&lt;/li&gt;
&lt;li&gt;WAS는 정적 리소스, 애플리케이션 로직 모두 제공 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;WAS가 너무 많은 역할을 담당, 서버 과부하 우려&lt;/li&gt;
&lt;li&gt;가장 비싼 애플리케이션 로직이 정적 리소스 때문에 수행이 어려울 수 있음&lt;/li&gt;
&lt;li&gt;WAS 장애시 오류 화면도 노출 불가능&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 웹 시스템 구성 - WEB, WAS, DB&amp;nbsp; &amp;nbsp;( 1 보다 좋다)&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 리소스는 웹 서버가 처리&lt;/li&gt;
&lt;li&gt;웹 서버는 애플리케이션 로직같은 동적인 처리가 필요하면 WAS에 요청을 위임&lt;/li&gt;
&lt;li&gt;WAS는 중요한 애플리케이션 로직 처리 전담&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;효율적인 리소스 관리&lt;br /&gt;- 정적 리소스가 많이 사용되면 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Web &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;서버 증설&lt;br /&gt;&lt;/span&gt;- 애플리케이션 리소스가 많이 사용되면 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;WAS &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;증설&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;정적 리소스만 제공하는 웹 서버는 잘 죽지 않음 but, 애플리케이션 로직이 동작하는 WAS 서버는 잘 죽음&lt;/li&gt;
&lt;li&gt;WAS, DB 장애시 WEB 서버가 오류 화면 제공 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring/mvc</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/49</guid>
      <comments>https://zeroone.tistory.com/49#entry49comment</comments>
      <pubDate>Sun, 5 Jun 2022 13:41:36 +0900</pubDate>
    </item>
    <item>
      <title>빈 스코프</title>
      <link>https://zeroone.tistory.com/48</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;빈 스코프란&lt;/span&gt;&lt;span&gt;? &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;빈이 존재할 수 있는 범위(기간)를 뜻한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;싱글톤: 기본 스코프, 스프링 컨테이너의 시작과 종료까지 유지되는 가장 넓은 범위의 스코프이다.&lt;/li&gt;
&lt;li&gt;프로토타입: 스프링 컨테이너는 프로토타입 빈의 생성과 의존관계 주입, 초기화까지만 관여하고 더는 관리하지 않는 매우 짧은 범위의 스코프이다.&lt;/li&gt;
&lt;li&gt;웹 관련 스코프&lt;/li&gt;
&lt;li&gt;request&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;웹 요청이 들어오고 나갈때 까지 유지되는 스코프이다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;session&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;웹 세션이 생성되고 종료될 때 까지 유지되는 스코프이다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;application&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;웹의 서블릿 컨텍스트와 같은 범위로 유지되는 스코프이다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;싱글톤과 프로토타입 빈 차이&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7yhpC/btrCNNC0gvi/FklA8rPdvMXN8aq8hOoARk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7yhpC/btrCNNC0gvi/FklA8rPdvMXN8aq8hOoARk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7yhpC/btrCNNC0gvi/FklA8rPdvMXN8aq8hOoARk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7yhpC%2FbtrCNNC0gvi%2FFklA8rPdvMXN8aq8hOoARk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;214&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. &lt;/span&gt;&lt;span&gt;싱글톤 스코프의 빈을 스프링 컨테이너에 요청한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;2. &lt;/span&gt;&lt;span&gt;스프링 컨테이너는 본인이 관리하는 스프링 빈을 반환한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;3. &lt;/span&gt;&lt;span&gt;이후에 스프링 컨테이너에 같은 요청이 와도 같은 객체 인스턴스의 스프링 빈을 반환한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DE4Q8/btrCQ78j1Ry/fyyMK67uIE2X6dU5xImwsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DE4Q8/btrCQ78j1Ry/fyyMK67uIE2X6dU5xImwsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DE4Q8/btrCQ78j1Ry/fyyMK67uIE2X6dU5xImwsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDE4Q8%2FbtrCQ78j1Ry%2FfyyMK67uIE2X6dU5xImwsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;214&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. &lt;/span&gt;&lt;span&gt;프로토타입 스코프의 빈을 스프링 컨테이너에 요청한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;2. &lt;/span&gt;&lt;span&gt;스프링 컨테이너는 이 시점에 프로토타입 빈을 생성하고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;필요한 의존관계를 주입한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zpwzz/btrCMYxYVtz/kplaUUbOk75pqcWPbblrXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zpwzz/btrCMYxYVtz/kplaUUbOk75pqcWPbblrXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zpwzz/btrCMYxYVtz/kplaUUbOk75pqcWPbblrXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZpwzz%2FbtrCMYxYVtz%2FkplaUUbOk75pqcWPbblrXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;214&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3. &lt;/span&gt;&lt;span&gt;스프링 컨테이너는 생성한 프로토타입 빈을 클라이언트에 반환한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;4. &lt;/span&gt;&lt;span&gt;이후에 스프링 컨테이너에 같은 요청이 오면 항상 새로운 프로토타입 빈을 생성해서 반환한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;*프로토타입 빈의 경우, 스프링 컨테이너에서 관리 안하므로 preDestroy같은 이벤트 발생안함!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;프로토타입 스코프 &lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;싱글톤 빈과 함께 사용시 문제점 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eCPUJG/btrCPIBcu4Y/ZX1oFVFrdosahX7gWBkO61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eCPUJG/btrCPIBcu4Y/ZX1oFVFrdosahX7gWBkO61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eCPUJG/btrCPIBcu4Y/ZX1oFVFrdosahX7gWBkO61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeCPUJG%2FbtrCPIBcu4Y%2FZX1oFVFrdosahX7gWBkO61%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;205&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;은 싱글톤이므로&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;보통 스프링 컨테이너 생성 시점에 함께 생성되고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;의존관계 주입도 발생한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;1. &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;은 의존관계 자동 주입을 사용한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;주입 시점에 스프링 컨테이너에 프로토타입 빈을 요청한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. &lt;/span&gt;&lt;span&gt;스프링 컨테이너는 프로토타입 빈을 생성해서 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;에 반환한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;프로토타입 빈의 &lt;/span&gt;&lt;span&gt;count &lt;/span&gt;&lt;span&gt;필드 값은 &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;이다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;이제 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;은 프로토타입 빈을 내부 필드에 보관한다&lt;/span&gt;&lt;span&gt;. (&lt;/span&gt;&lt;span&gt;정확히는 참조값을 보관한다&lt;/span&gt;&lt;span&gt;.) &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzbusM/btrCRRqTJC0/g3Lbn74n2rbYzdrQhK81zK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzbusM/btrCRRqTJC0/g3Lbn74n2rbYzdrQhK81zK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzbusM/btrCRRqTJC0/g3Lbn74n2rbYzdrQhK81zK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzbusM%2FbtrCRRqTJC0%2Fg3Lbn74n2rbYzdrQhK81zK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;205&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;466&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트 &lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;을 스프링 컨테이너에 요청해서 받는다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;싱글톤이므로 항상 같은 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;이 반환된다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;3. &lt;/span&gt;&lt;span&gt;클라이언트 &lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean.logic() &lt;/span&gt;&lt;span&gt;을 호출한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;4. &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;은 &lt;/span&gt;&lt;span&gt;prototypeBean&lt;/span&gt;&lt;span&gt;의 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;addCount() &lt;/span&gt;&lt;span&gt;를 호출해서 프로토타입 빈의 &lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;를 증가한다&lt;/span&gt;&lt;span&gt;. count&lt;/span&gt;&lt;span&gt;값이 &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;이 된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;464&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nTevT/btrCLz6w3lX/jFB2WW7XczlyWM56JLcWVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nTevT/btrCLz6w3lX/jFB2WW7XczlyWM56JLcWVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nTevT/btrCLz6w3lX/jFB2WW7XczlyWM56JLcWVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnTevT%2FbtrCLz6w3lX%2FjFB2WW7XczlyWM56JLcWVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;204&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;464&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트 &lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;을 스프링 컨테이너에 요청해서 받는다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;싱글톤이므로 항상 같은 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;이 반환된다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;여기서 중요한 점이 있는데&lt;/span&gt;&lt;span&gt;, clientBean&lt;/span&gt;&lt;span&gt;이 내부에 가지고 있는 프로토타입 빈은 이미 과거에 주입이 끝난 빈이다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;주입 시점에 스프링 컨테이너에 요청해서 프로토타입 빈이 새로 생성이 된 것이지&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;사용 할 때마다 새로 생성되는 것이 아니다&lt;/span&gt;&lt;span&gt;!&lt;br /&gt;&lt;/span&gt;&lt;span&gt;5. &lt;/span&gt;&lt;span&gt;클라이언트 &lt;/span&gt;&lt;span&gt;B&lt;/span&gt;&lt;span&gt;는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean.logic() &lt;/span&gt;&lt;span&gt;을 호출한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;6. &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;clientBean &lt;/span&gt;&lt;span&gt;은 &lt;/span&gt;&lt;span&gt;prototypeBean&lt;/span&gt;&lt;span&gt;의 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;addCount() &lt;/span&gt;&lt;span&gt;를 호출해서 프로토타입 빈의 &lt;/span&gt;&lt;span&gt;count&lt;/span&gt;&lt;span&gt;를 증가한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;원래 &lt;/span&gt;&lt;span&gt;count &lt;/span&gt;&lt;span&gt;값이 &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;이었으므로 &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;가 된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1653209917505&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.scope;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Scope;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import static org.assertj.core.api.Assertions.*;

public class SingletonWithPrototypeTest1 {
    @Test
    void singletonClientUsePrototype() {
        AnnotationConfigApplicationContext ac = new
AnnotationConfigApplicationContext(ClientBean.class, PrototypeBean.class);
        ClientBean clientBean1 = ac.getBean(ClientBean.class);
        int count1 = clientBean1.logic();
        assertThat(count1).isEqualTo(1);
        ClientBean clientBean2 = ac.getBean(ClientBean.class);
        int count2 = clientBean2.logic();
        assertThat(count2).isEqualTo(2);
    }
    static class ClientBean {
        private final PrototypeBean prototypeBean;
        @Autowired
        public ClientBean(PrototypeBean prototypeBean) {
            this.prototypeBean = prototypeBean;
        }
        public int logic() {
            prototypeBean.addCount();
            int count = prototypeBean.getCount();
            return count;
        } 
    }
    @Scope(&quot;prototype&quot;)
    static class PrototypeBean {
        private int count = 0;
        public void addCount() {
            count++; 
        }
        public int getCount() {
             return count;
        }
        @PostConstruct
        public void init() {
             System.out.println(&quot;PrototypeBean.init &quot; + this);
        }
        @PreDestroy
        public void destroy() {
            System.out.println(&quot;PrototypeBean.destroy&quot;);
        }
    } 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;프로토타입 스코프 &lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;싱글톤 빈과 함께 사용시 &lt;/span&gt;&lt;span&gt;Provider&lt;/span&gt;&lt;span&gt;로 문제 해결&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;방안 1. &lt;span&gt;Dependency Lookup (DL)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;의존관계 조회(탐색) : &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;의존관계를 외부에서 주입&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(DI) &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;받는게 아니라 이렇게 직접 필요한 의존관계를 찾는 것&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 컨테이너에 의존&lt;/li&gt;
&lt;li&gt;단위테스트 작성이 어렵다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1653210187542&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Autowired
private ApplicationContext ac;
public int logic() {
    PrototypeBean prototypeBean = ac.getBean(PrototypeBean.class);
    prototypeBean.addCount();
    int count = prototypeBean.getCount();
    return count;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 나은 방안 2. &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;ObjectFactory, ObjectProvider : &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;지정한 빈을 컨테이너에서 대신 찾아주는 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;DL &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;서비스를 제공하는 것&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ObjectFactory + 편의기능 추가 -&amp;gt; ObjectProvider&lt;/li&gt;
&lt;li&gt;스프링에 의존&lt;/li&gt;
&lt;li&gt;기능이 단순하여 단위테스트 작성에 쉽다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1653210551791&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Autowired
private ObjectProvider&amp;lt;PrototypeBean&amp;gt; prototypeBeanProvider;
public int logic() {
    PrototypeBean prototypeBean = prototypeBeanProvider.getObject();
    prototypeBean.addCount();
    int count = prototypeBean.getCount();
    return count;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 나은 방안 3. &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;JSR-330 Provider : &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;javax.inject.Provider &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;라는 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;JSR-330 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;자바 표준 DL 서비스 제공&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;java 표준으로 스프링 의존 x&lt;/li&gt;
&lt;li&gt;기능이 단순하여 단위테스트 작성에 쉽다&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;package javax.inject;
public interface Provider&amp;lt;T&amp;gt; {
      T get(); 
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;/implementation 'javax.inject:javax.inject:1' gradle 추가 필수 
@Autowired
private Provider&amp;lt;PrototypeBean&amp;gt; provider;

public int logic() {
      PrototypeBean prototypeBean = provider.get();
      prototypeBean.addCount();
      int count = prototypeBean.getCount();
      return count;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;웹 스코프 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹 스코프의 특징 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 스코프는 웹 환경에서만 동작한다.&lt;/li&gt;
&lt;li&gt;웹 스코프는 프로토타입과 다르게 스프링이 해당 스코프의 종료시점까지 관리한다. 따라서 종료 메서드가 호출된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cc95dV/btrCOK67ORs/g09zqJXL1oKHE4EB0nhRXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cc95dV/btrCOK67ORs/g09zqJXL1oKHE4EB0nhRXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cc95dV/btrCOK67ORs/g09zqJXL1oKHE4EB0nhRXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcc95dV%2FbtrCOK67ORs%2Fg09zqJXL1oKHE4EB0nhRXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;189&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;request 스코프 예제&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;웹 환경 추가 - build.gradle&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1653211327979&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//web 라이브러리 추가
implementation 'org.springframework.boot:spring-boot-starter-web'&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;spring-boot-starter-web &lt;/span&gt;&lt;span&gt;라이브러리를 추가하면 스프링 부트는 내장 톰켓 서버를 활용해서 웹 서버와 스프링을 함께 실행시킨다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링 부트는 웹 라이브러리가 없으면 우리가 지금까지 학습한 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;AnnotationConfigApplicationContext &lt;/span&gt;&lt;span&gt;을 기반으로 애플리케이션을 구동한다&lt;/span&gt;&lt;span&gt;.&amp;nbsp; &lt;/span&gt;&lt;span&gt;웹 라이브러리가 추가되면 웹과 관련된 추가 설정과 환경들이 &lt;/span&gt;&lt;span&gt;필요하므로&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;AnnotationConfigServletWebServerApplicationContext &lt;/span&gt;&lt;span&gt;를 기반으로 애플리케이션을 구동한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;lt;MyLogger&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1653211596620&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.common;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.UUID;
@Component
@Scope(value = &quot;request&quot;)
public class MyLogger {
    private String uuid;
    private String requestURL;
    public void setRequestURL(String requestURL) {
        this.requestURL = requestURL;
    }
    public void log(String message) {
        System.out.println(&quot;[&quot; + uuid + &quot;]&quot; + &quot;[&quot; + requestURL + &quot;] &quot; + message); 
    }
    @PostConstruct
    public void init() {
        uuid = UUID.randomUUID().toString();
        System.out.println(&quot;[&quot; + uuid + &quot;] request scope bean create:&quot; + this);
    }
    @PreDestroy
    public void close() {
        System.out.println(&quot;[&quot; + uuid + &quot;] request scope bean close:&quot; + this);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;LogDemoController&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1653211872366&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  package hello.core.web;
  import hello.core.common.MyLogger;
  import hello.core.logdemo.LogDemoService;
  import lombok.RequiredArgsConstructor;
  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.ResponseBody;
  import javax.servlet.http.HttpServletRequest;
  @Controller
  @RequiredArgsConstructor
  public class LogDemoController {
           private final LogDemoService logDemoService;
        private final MyLogger myLogger;
        @RequestMapping(&quot;log-demo&quot;)
        @ResponseBody
        public String logDemo(HttpServletRequest request) {
            String requestURL = request.getRequestURL().toString();
            myLogger.setRequestURL(requestURL);
            myLogger.log(&quot;controller test&quot;);
            logDemoService.logic(&quot;testId&quot;);
            return &quot;OK&quot;;
} }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;LogDemoService&lt;/span&gt;&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1653211897467&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.logdemo;
    import hello.core.common.MyLogger;
    import lombok.RequiredArgsConstructor;
    import org.springframework.stereotype.Service;
       @Service
  @RequiredArgsConstructor
  public class LogDemoService {
      private final MyLogger myLogger;
      public void logic(String id) {
          myLogger.log(&quot;service id = &quot; + id);
} }&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링 애플리케이션을 실행하는 시점에 싱글톤 빈은 생성해서 주입이 가능하지만&lt;/span&gt;&lt;span&gt;, request &lt;/span&gt;&lt;span&gt;스코프 빈은 아직 생성되지 않는다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;이 빈은 실제 고객의 요청이 와야 생성할 수 있다&lt;/span&gt;&lt;span&gt;! &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;Provider를 사용한 LogDemoService&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1653212018549&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.logdemo;
  import hello.core.common.MyLogger;
  import lombok.RequiredArgsConstructor;
  import org.springframework.beans.factory.ObjectProvider;
  import org.springframework.stereotype.Service;
  @Service
  @RequiredArgsConstructor
  public class LogDemoService {
      private final ObjectProvider&amp;lt;MyLogger&amp;gt; myLoggerProvider;
      public void logic(String id) {
          MyLogger myLogger = myLoggerProvider.getObject();
          myLogger.log(&quot;service id = &quot; + id);
} }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;프록시를 사용한 myLogger&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1653212143096&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; @Component
  @Scope(value = &quot;request&quot;, proxyMode = ScopedProxyMode.TARGET_CLASS)
  public class MyLogger {
  }&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;proxyMode = ScopedProxyMode.TARGET_CLASS &lt;/span&gt;&lt;span&gt;를 추가&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;적용 대상이 인터페이스가 아닌 클래스면 TARGET_CLASS 를 선택&lt;/li&gt;
&lt;li&gt;적용 대상이 인터페이스면 INTERFACES 를 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 하면 &lt;/span&gt;&lt;span&gt;MyLogger&lt;/span&gt;&lt;span&gt;의 가짜 프록시 클래스를 만들어두고 &lt;/span&gt;&lt;span&gt;HTTP request&lt;/span&gt;&lt;span&gt;와 상관 없이 가짜 프록시 클래스를 다른 빈에 미리 주입해 둘 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;CGLIB&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;라는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8ENWQ/btrCQv9vJD0/Vh68YEktW4JCfNOOvTXjt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8ENWQ/btrCQv9vJD0/Vh68YEktW4JCfNOOvTXjt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8ENWQ/btrCQv9vJD0/Vh68YEktW4JCfNOOvTXjt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8ENWQ%2FbtrCQv9vJD0%2FVh68YEktW4JCfNOOvTXjt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;189&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;동작 정리 &lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;CGLIB라는 라이브러리로 내 클래스를 상속 받은 가짜 프록시 객체를 만들어서 주입한다.&lt;/li&gt;
&lt;li&gt;이 가짜 프록시 객체는 실제 요청이 오면 그때 내부에서 실제 빈을 요청하는 위임 로직이 들어있다.&lt;/li&gt;
&lt;li&gt;가짜 프록시 객체는 실제 request scope와는 관계가 없다. 그냥 가짜이고, 내부에 단순한 위임 로직만 있고, 싱글톤 처럼 동작한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;특징 정리 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프록시 객체 덕분에 클라이언트는 마치 싱글톤 빈을 사용하듯이 편리하게 request scope를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;사실 Provider를 사용하든, 프록시를 사용하든 핵심 아이디어는 진짜 객체 조회를 꼭 필요한 시점까지 지연처리 한다는 점이다.&lt;/li&gt;
&lt;li&gt;단지 애노테이션 설정 변경만으로 원본 객체를 프록시 객체로 대체할 수 있다. 이것이 바로 다형성과 DI 컨테이너가 가진 큰 강점이다.&lt;/li&gt;
&lt;li&gt;꼭 웹 스코프가 아니어도 프록시는 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;주의점 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;마치 싱글톤을 사용하는 것 같지만 다르게 동작하기 때문에 결국 주의해서 사용해야 한다.&lt;/li&gt;
&lt;li&gt;이런 특별한 scope는 꼭 필요한 곳에만 최소화해서 사용하자, 무분별하게 사용하면 유지보수하기 어려워진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Spring/core</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/48</guid>
      <comments>https://zeroone.tistory.com/48#entry48comment</comments>
      <pubDate>Sun, 22 May 2022 18:44:43 +0900</pubDate>
    </item>
    <item>
      <title>빈 생명주기 콜백</title>
      <link>https://zeroone.tistory.com/47</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;스프링 빈의 이벤트 라이프사이클&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링 컨테이너 생성 -&amp;gt; 스프링 빈 생성 -&amp;gt; 의존관계 주입 -&amp;gt; 초기화 콜백 -&amp;gt; 사용 -&amp;gt; 소멸전 콜백 -&amp;gt; 스프링 종료 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; * 생성자 주입의 경우, 스프링 빈 생성될 때 주입 발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링은 크게 &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;가지 방법으로 빈 생명주기 콜백을 지원한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터페이스(InitializingBean, DisposableBean)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1651900461882&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.lifecycle;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class NetworkClient implements InitializingBean, DisposableBean {
    private String url;

	public NetworkClient() { System.out.println(&quot;생성자 호출, url = &quot; + url); }
    
    public void setUrl(String url) { this.url = url; }

	//서비스 시작시 호출
    public void connect() {
        System.out.println(&quot;connect: &quot; + url);
    }
    
    public void call(String message) {
        System.out.println(&quot;call: &quot; + url + &quot; message = &quot; + message);
    }
    
	//서비스 종료시 호출
    public void disConnect() {
        System.out.println(&quot;close + &quot; + url);
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
    	connect();
        call(&quot;초기화 연결 메시지&quot;);
    }
    
    @Override
    public void destroy() throws Exception {
    	disConnect();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설정 정보에 초기화 메서드, 종료 메서드 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1651900733335&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.lifecycle;

public class NetworkClient {

    private String url;

    public NetworkClient() {
        System.out.println(&quot;생정자 호출, url = &quot; + url);
    }

    public void setUrl(String url) {
        this.url = url;
    }

    // 서비스 시작시 호출
    public void connect() {
        System.out.println(&quot;connect: &quot; + url);
    }

    public void call(String message) {
        System.out.println(&quot;call: &quot; + url + &quot; message = &quot; + message);
    }

    // 서비스 종료시 호출
    public void disconnect() {
        System.out.println(&quot;close: &quot; + url);
    }

    public void init() {
        System.out.println(&quot;NetworkClient.init&quot;);
        connect();
        call(&quot;초기화 연결 메시지&quot;);
    }

    public void close() throws Exception {
        System.out.println(&quot;NetworkClient.close&quot;);
        disconnect();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1651900639916&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
static class LifeCycleConfig {
    @Bean(initMethod = &quot;init&quot;, destroyMethod = &quot;close&quot;)
    public NetworkClient networkClient() {
        NetworkClient networkClient = new NetworkClient();
        networkClient.setUrl(&quot;http://hello-spring.dev&quot;);
        return networkClient;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@PostConstruct, @PreDestroy 애노테이션 지원(권장)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1651900756471&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package lifecycle;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class NetworkClient {

    private String url;

    public NetworkClient() {
        System.out.println(&quot;생정자 호출, url = &quot; + url);
    }

    public void setUrl(String url) {
        this.url = url;
    }

    // 서비스 시작시 호출
    public void connect() {
        System.out.println(&quot;connect: &quot; + url);
    }

    public void call(String message) {
        System.out.println(&quot;call: &quot; + url + &quot; message = &quot; + message);
    }

    // 서비스 종료시 호출
    public void disconnect() {
        System.out.println(&quot;close: &quot; + url);
    }

    @PostConstruct
    public void init() {
        System.out.println(&quot;NetworkClient.init&quot;);
        connect();
        call(&quot;초기화 연결 메시지&quot;);
    }

    @PreDestroy
    public void close() throws Exception {
        System.out.println(&quot;NetworkClient.close&quot;);
        disconnect();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring/core</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/47</guid>
      <comments>https://zeroone.tistory.com/47#entry47comment</comments>
      <pubDate>Sat, 7 May 2022 14:21:52 +0900</pubDate>
    </item>
    <item>
      <title>의존관계 자동 주입</title>
      <link>https://zeroone.tistory.com/46</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;다양한 의존관계 주입(@Autowired) 방법&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자 주입&lt;/li&gt;
&lt;li&gt;수정자 주입(setter 주입)&lt;/li&gt;
&lt;li&gt;필드 주입&lt;/li&gt;
&lt;li&gt;일반 메서드 주입&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;참고&lt;/span&gt;&lt;span&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Autowired&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;의 기본 동작은 주입할 대상이 없으면 오류가 발생한다&lt;/span&gt;&lt;span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;주입할 대상이 없어도 동작하게 하려면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Autowired(required = false)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;로 지정하면 된다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자 주입&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자 호출시점에 딱 1번만 호출되는 것이 보장된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;불변, 필수&lt;/b&gt; 의존관계에 사용&lt;/li&gt;
&lt;li&gt;중요&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;! &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;생성자가 딱 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;개만 있으면 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;@Autowired&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;를 생략해도 자동 주입 된다. &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;물론 스프링 빈에만 해당한다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;수정자 주입&lt;/span&gt;&lt;span&gt;(setter &lt;/span&gt;&lt;span&gt;주입&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;선택, 변경&lt;/b&gt; 가능성이 있는 의존관계에 사용&lt;/li&gt;
&lt;li&gt;자바빈 프로퍼티 규약의 수정자 메서드 방식을 사용하는 방법이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;필드 주입 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드가 간결해서 많은 개발자들을 유혹하지만 외부에서 변경이 불가능해서 테스트 하기 힘들다는 치명적인 단점이 있다.&lt;/li&gt;
&lt;li&gt;DI 프레임워크가 없으면 아무것도 할 수 없다.&lt;/li&gt;
&lt;li&gt;사용하지 말자!&lt;/li&gt;
&lt;li&gt;애플리케이션의 실제 코드와 관계 없는 테스트 코드 또는 스프링 설정을 목적으로 하는 @Configuration 같은 곳에서만 특별한 용도로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일반 메서드 주입 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한번에 여러 필드를 주입 받을 수 있다.&lt;/li&gt;
&lt;li&gt;일반적으로 잘 사용하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자동 주입 대상 옵션처리&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Autowired(required=false) : 자동 주입할 대상이 없으면 수정자 메서드 자체가 호출 안됨&lt;/li&gt;
&lt;li&gt;org.springframework.lang.@Nullable : 자동 주입할 대상이 없으면 null이 입력된다.&lt;/li&gt;
&lt;li&gt;Optional&amp;lt;&amp;gt; : 자동 주입할 대상이 없으면 Optional.empty 가 입력된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1649606458738&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//호출 안됨
@Autowired(required = false)
public void setNoBean1(Member member) {
        System.out.println(&quot;setNoBean1 = &quot; + member);
    }
//null 호출
@Autowired
public void setNoBean2(@Nullable Member member) {
        System.out.println(&quot;setNoBean2 = &quot; + member);
    }
//Optional.empty 호출
@Autowired(required = false)
public void setNoBean3(Optional&amp;lt;Member&amp;gt; member) {
        System.out.println(&quot;setNoBean3 = &quot; + member);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론 : 주입방식은 생성자 주입을 선택하라&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;불변 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;대부분의 의존관계 주입은 한번 일어나면 애플리케이션 종료시점까지 의존관계를 변경할 일이 없다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;오히려 대부분의 의존관계는 애플리케이션 종료 전까지 변하면 안된다&lt;/span&gt;&lt;span&gt;.(&lt;/span&gt;&lt;span&gt;불변해야 한다&lt;/span&gt;&lt;span&gt;.)&lt;br /&gt;&lt;/span&gt;&lt;span&gt;수정자 주입을 사용하면&lt;/span&gt;&lt;span&gt;, setXxx &lt;/span&gt;&lt;span&gt;메서드를 &lt;/span&gt;&lt;span&gt;public&lt;/span&gt;&lt;span&gt;으로 열어두어야 한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;누군가 실수로 변경할 수 도 있고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;변경하면 안되는 메서드를 열어두는 것은 좋은 설계 방법이 아니다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;생성자 주입은 객체를 생성할 때 딱 &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;번만 호출되므로 이후에 호출되는 일이 없다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;따라서 불변하게 설계할 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;누락 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;프레임워크 없이 순수한 자바 코드를 단위 테스트 하는 경우에 생성자 주입을 사용하면 컴파일 오류가 발생한다. -&amp;gt; 실행하기 전에 오류 캐치가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;롬복과 최신 트랜드 &lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;롬복 라이브러리가 제공하는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@RequiredArgsConstructor &lt;/span&gt;&lt;span&gt;기능을 사용하면 &lt;/span&gt;&lt;span&gt;final&lt;/span&gt;&lt;span&gt;이 붙은 필드를 모아서 생성자를 자동으로 만들어준다&lt;/span&gt;&lt;span&gt;. (&lt;/span&gt;&lt;span&gt;다음 코드에는 보이지 않지만 실제 호출 가능하다&lt;/span&gt;&lt;span&gt;.)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1649606724032&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; @Component
 @RequiredArgsConstructor
 public class OrderServiceImpl implements OrderService {
      private final MemberRepository memberRepository;
      private final DiscountPolicy discountPolicy;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;class 파일에서 밑에 코드 추가된다.&lt;/p&gt;
&lt;pre id=&quot;code_1649606764548&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy
  discountPolicy) {
      this.memberRepository = memberRepository;
      this.discountPolicy = discountPolicy;
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;롬복을 이용하면 코드가 깔끔해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;조회 빈이 &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;개 이상 &lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;문제 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1649607235929&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; @Autowired
  private DiscountPolicy discountPolicy&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1649607274002&quot; class=&quot;angelscript&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
  public class FixDiscountPolicy implements DiscountPolicy {}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1649607297730&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
  public class RateDiscountPolicy implements DiscountPolicy {}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과 : 에러&lt;/p&gt;
&lt;pre id=&quot;code_1649607314217&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  NoUniqueBeanDefinitionException: No qualifying bean of type
  'hello.core.discount.DiscountPolicy' available: expected single matching bean
  but found 2: fixDiscountPolicy,rateDiscountPolicy&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해결방법&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. @Autowired &lt;/span&gt;&lt;span&gt;필드 명 매칭 (필드 명을 빈 이름으로 변경)&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1649607374805&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  @Autowired
  private DiscountPolicy rateDiscountPolicy&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;@Autowired &lt;/span&gt;&lt;span&gt;매칭 정리&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 1) &lt;/span&gt;&lt;span&gt;타입 매칭&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 2) &lt;/span&gt;&lt;span&gt;타입 매칭의 결과가 &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;개 이상일 때 필드 명&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;파라미터 명으로 빈 이름 매칭 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. @Qualifier &lt;/span&gt;&lt;span&gt;사용&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Qualifier &lt;/span&gt;&lt;span&gt;는 추가 구분자를 붙여주는 방법이다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;주입시 추가적인 방법을 제공하는 것이지 빈 이름을 변경하는 것은 아니다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;lt;빈 등록시 @Qualifier 붙임&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650182988460&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
@Qualifier(&quot;mainDiscountPolicy&quot;)
public class RateDiscountPolicy implements DiscountPolicy {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;자동주입&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650183033059&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  @Autowired
  public OrderServiceImpl(MemberRepository memberRepository,
                          @Qualifier(&quot;mainDiscountPolicy&quot;) DiscountPolicy
  discountPolicy) {
      this.memberRepository = memberRepository;
      this.discountPolicy = discountPolicy;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Qualifier &lt;/span&gt;&lt;span&gt;로 주입할 때 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Qualifier(&quot;mainDiscountPolicy&quot;) &lt;/span&gt;&lt;span&gt;를 못찾으면 어떻게 될까&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Qualifier 정리&lt;br /&gt;&amp;nbsp; &amp;nbsp; 1) @Qualifier끼리 매칭&lt;br /&gt;&amp;nbsp; &amp;nbsp; 2) 빈 이름 매칭&lt;br /&gt;&amp;nbsp; &amp;nbsp; 3) NoSuchBeanDefinitionException 예외 발생&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3. @Primary 사용&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Primary &lt;/span&gt;&lt;span&gt;는 우선순위를 정하는 방법이다&lt;/span&gt;&lt;span&gt;. @Autowired &lt;/span&gt;&lt;span&gt;시에 여러 빈이 매칭되면 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Primary &lt;/span&gt;&lt;span&gt;가 우선권을 가진다 &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650183262891&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
@Primary
public class RateDiscountPolicy implements DiscountPolicy {}

@Component
public class FixDiscountPolicy implements DiscountPolicy {}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;@Primary, @Qualifier &lt;/span&gt;&lt;span&gt;활용&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메인 데이터베이스 커넥션을 획득하는 스프링 빈 - @Primary&lt;/li&gt;
&lt;li&gt;서브 데이터베이스 커넥션을 획득하는 스프링 빈 - @Qualifier&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;우선순위&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;&amp;nbsp; &amp;nbsp;@Qualifer(상세) &amp;gt; @Primary(넓음)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애너테이션 직접 만들기&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Qualifier(&quot;mainDiscountPolicy&quot;) &lt;/span&gt;&lt;span&gt;이렇게 문자를 적으면 컴파일시 타입 체크가 안된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;다음과 같은 애노테이션을 만들어서 문제를 해결할 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1650198993533&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.annotataion;
import org.springframework.beans.factory.annotation.Qualifier;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier(&quot;mainDiscountPolicy&quot;)
public @interface MainDiscountPolicy {
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1650199036444&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
@MainDiscountPolicy
public class RateDiscountPolicy implements DiscountPolicy {}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1650199053398&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//생성자 자동 주입
@Autowired
public OrderServiceImpl(MemberRepository memberRepository,
                          @MainDiscountPolicy DiscountPolicy discountPolicy) {
      this.memberRepository = memberRepository;
      this.discountPolicy = discountPolicy;
}
//수정자 자동 주입
@Autowired
public DiscountPolicy setDiscountPolicy(@MainDiscountPolicy DiscountPolicy discountPolicy) {
      return discountPolicy;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;애노테이션에는 상속이라는 개념이 없다&lt;/span&gt;&lt;span&gt;. &lt;br /&gt;&lt;/span&gt;&lt;span&gt;이렇게 여러 애노테이션을 모아서 사용하는 기능은 스프링이 지원해주는 기능이다&lt;/span&gt;&lt;span&gt;.--&amp;gt;???&lt;br /&gt;@Qulifier &lt;/span&gt;&lt;span&gt;뿐만 아니라 다른 애노테이션들도 함께 조합해서 사용할 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;단적으로 &lt;/span&gt;&lt;span&gt;@Autowired&lt;/span&gt;&lt;span&gt;도 재정의 할 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;물론 스프링이 제공하는 기능을 뚜렷한 목적 없이 무분별하게 재정의 하는 것은 유지보수에 더 혼란만 가중할 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;조회한 빈이 모두 필요할 때&lt;/span&gt;&lt;span&gt;, List, Map &lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1650700396825&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class AllBeanTest {
    @Test
    void findAllBean() {
    	// 컴포넌트 스캔(AutoAppConfig)으로 등록한 빈들을 DiscountService에 저장
          ApplicationContext ac = new AnnotationConfigApplicationContext(AutoAppConfig.class, DiscountService.class);
          DiscountService discountService = ac.getBean(DiscountService.class);
          Member member = new Member(1L, &quot;userA&quot;, Grade.VIP);
          int discountPrice = discountService.discount(member, 10000, &quot;fixDiscountPolicy&quot;);
          assertThat(discountService).isInstanceOf(DiscountService.class);
          assertThat(discountPrice).isEqualTo(1000);
    }
    static class DiscountService {
    	private final Map&amp;lt;String, DiscountPolicy&amp;gt; policyMap;
        private final List&amp;lt;DiscountPolicy&amp;gt; policies;
        public DiscountService(Map&amp;lt;String, DiscountPolicy&amp;gt; policyMap, List&amp;lt;DiscountPolicy&amp;gt; policies) {
            this.policyMap = policyMap;
            this.policies = policies;
            System.out.println(&quot;policyMap = &quot; + policyMap);
            System.out.println(&quot;policies = &quot; + policies);
        }
        public int discount(Member member, int price, String discountCode) {
        	DiscountPolicy discountPolicy = policyMap.get(discountCode);
            System.out.println(&quot;discountCode = &quot; + discountCode);
            System.out.println(&quot;discountPolicy = &quot; + discountPolicy);
            return discountPolicy.discount(member, price);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;주입 분석 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Map&amp;lt;String, DiscountPolicy&amp;gt; : map의 키에 스프링 빈의 이름을 넣어주고, 그 값으로 DiscountPolicy 타입으로 조회한 모든 스프링 빈을 담아준다.&lt;/li&gt;
&lt;li&gt;List&amp;lt;DiscountPolicy&amp;gt; : DiscountPolicy 타입으로 조회한 모든 스프링 빈을 담아준다.&lt;/li&gt;
&lt;li&gt;만약 해당하는 타입의 스프링 빈이 없으면, 빈 컬렉션이나 Map을 주입한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;자동&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;수동의 올바른 실무 운영 기준&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;편리한 자동 기능을 기본으로 사용하자.&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;업무 로직 빈: 웹을 지원하는 컨트롤러, 핵심 비즈니스 로직이 있는 서비스, 데이터 계층의 로직을 처리하는 리포지토리등이 모두 업무 로직이다. 보통 비즈니스 요구사항을 개발할 때 추가되거나 변경된다. -&amp;gt; 잘 적용되는지 파악하기 어렵다. 자동 빈 등록&lt;/li&gt;
&lt;li&gt;기술 지원 빈: 기술적인 문제나 공통 관심사(AOP)를 처리할 때 주로 사용된다. 데이터베이스 연결이나, 공통 로그 처리 처럼 업무 로직을 지원하기 위한 하부 기술이나 공통 기술들이다 -&amp;gt; 잘 적용되는지 파악하기 어렵다. 수동 빈 등록이 유지보수에 좋다&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;비즈니스 로직 중에서 다형성을 적극 활용할 때 &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;의존관계 자동 주입 &lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;조회한 빈이 모두 필요할 때&lt;/span&gt;&lt;span&gt;, List, Map&lt;/span&gt;&lt;span&gt;을 다시 보자&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;DiscountService &lt;/span&gt;&lt;span&gt;가 의존관계 자동 주입으로 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;Map&amp;lt;String, DiscountPolicy&amp;gt; &lt;/span&gt;&lt;span&gt;에 주입을 받는 상황을 생각해보자&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;여기에 어떤 빈들이 주입될 지&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;각 빈들의 이름은 무엇일지 코드만 보고 한번에 쉽게 파악할 수 있을까&lt;/span&gt;&lt;span&gt;? &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 경우 수동 빈으로 등록하거나 또는 자동으로하면 &lt;/span&gt;&lt;span&gt;특정 패키지에 같이 묶어&lt;/span&gt;&lt;span&gt;두는게 좋다&lt;/span&gt;&lt;span&gt;! &lt;/span&gt;&lt;span&gt;핵심은 딱 보고 이해가 되어야 한다&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1650703240398&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
  public class DiscountPolicyConfig {
      @Bean
      public DiscountPolicy rateDiscountPolicy() {
          return new RateDiscountPolicy();
      }
      @Bean
      public DiscountPolicy fixDiscountPolicy() {
          return new FixDiscountPolicy();
      }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Spring/core</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/46</guid>
      <comments>https://zeroone.tistory.com/46#entry46comment</comments>
      <pubDate>Sat, 23 Apr 2022 17:41:53 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Collection 정렬</title>
      <link>https://zeroone.tistory.com/45</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Collection.sort를 하기위해선 class 내에 Comparator나 comparable&amp;lt;T&amp;gt;를&amp;nbsp; 구현해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, compareTo 메서드를 오버라이딩 해야한다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;    @Override
    public int compareTo(Student o) {
    	// 구현
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 때, 어떤 기준으로 1, 0, -1을 리턴해줘야 하는지 자주 헷갈려서 소스를 분석했다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648993193899&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public static &amp;lt;T extends Comparable&amp;lt;? super T&amp;gt;&amp;gt; void sort(List&amp;lt;T&amp;gt; list) {
        list.sort(null);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Collections.sort()도 결국은 Array로 변환해 Arrays.sort를 호출한다&lt;/p&gt;
&lt;pre id=&quot;code_1648993248798&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    default void sort(Comparator&amp;lt;? super E&amp;gt; c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator&amp;lt;E&amp;gt; i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Comparator가 있을 경우, LegacyMergerSort.userRequested 는 false로 TimSort를 수행한다&lt;/p&gt;
&lt;pre id=&quot;code_1648993274006&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public static &amp;lt;T&amp;gt; void sort(T[] a, Comparator&amp;lt;? super T&amp;gt; c) {
        if (c == null) {
            sort(a);
        } else {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a, c);
            else
                TimSort.sort(a, 0, a.length, c, null, 0, 0);
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Comparator가 없을 경우, LegacyMergerSort.userRequested 는 false로 ComparableTimSort를 수행한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1648994038267&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    public static void sort(Object[] a) {
        if (LegacyMergeSort.userRequested)
            legacyMergeSort(a);
        else
            ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Comparartor가 있던 없던, TimSort과 ComparableTimSort 내부에서 countRunAndMakeAscending, binarySort를 실행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1648993422115&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    static &amp;lt;T&amp;gt; void sort(T[] a, int lo, int hi, Comparator&amp;lt;? super T&amp;gt; c,
                         T[] work, int workBase, int workLen) {
        assert c != null &amp;amp;&amp;amp; a != null &amp;amp;&amp;amp; lo &amp;gt;= 0 &amp;amp;&amp;amp; lo &amp;lt;= hi &amp;amp;&amp;amp; hi &amp;lt;= a.length;

        int nRemaining  = hi - lo;
        if (nRemaining &amp;lt; 2)
            return;  // Arrays of size 0 and 1 are always sorted

        // If array is small, do a &quot;mini-TimSort&quot; with no merges
        if (nRemaining &amp;lt; MIN_MERGE) {
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c);
            return;
        }

        /**
         * March over the array once, left to right, finding natural runs,
         * extending short natural runs to minRun elements, and merging runs
         * to maintain stack invariant.
         */
        TimSort&amp;lt;T&amp;gt; ts = new TimSort&amp;lt;&amp;gt;(a, c, work, workBase, workLen);
        int minRun = minRunLength(nRemaining);
        do {
            // Identify next run
            int runLen = countRunAndMakeAscending(a, lo, hi, c);

            // If run is short, extend to min(minRun, nRemaining)
            if (runLen &amp;lt; minRun) {
                int force = nRemaining &amp;lt;= minRun ? nRemaining : minRun;
                binarySort(a, lo, lo + force, lo + runLen, c);
                runLen = force;
            }

            // Push run onto pending-run stack, and maybe merge
            ts.pushRun(lo, runLen);
            ts.mergeCollapse();

            // Advance to find next run
            lo += runLen;
            nRemaining -= runLen;
        } while (nRemaining != 0);

        // Merge all remaining runs to complete sort
        assert lo == hi;
        ts.mergeForceCollapse();
        assert ts.stackSize == 1;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 compareTo가 실행된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1648994176114&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    private static int countRunAndMakeAscending(Object[] a, int lo, int hi) {
        assert lo &amp;lt; hi;
        int runHi = lo + 1;
        if (runHi == hi)
            return 1;

        // Find end of run, and reverse range if descending
        if (((Comparable) a[runHi++]).compareTo(a[lo]) &amp;lt; 0) { // Descending
            while (runHi &amp;lt; hi &amp;amp;&amp;amp; ((Comparable) a[runHi]).compareTo(a[runHi - 1]) &amp;lt; 0)
                runHi++;
            reverseRange(a, lo, runHi);
        } else {                              // Ascending
            while (runHi &amp;lt; hi &amp;amp;&amp;amp; ((Comparable) a[runHi]).compareTo(a[runHi - 1]) &amp;gt;= 0)
                runHi++;
        }

        return runHi - lo;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, compareTo는 이전 배열원소들이랑 비교하여 0보다 작은 값을 return하면 자리를 스왑한다!!!&lt;/p&gt;</description>
      <category>Java</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/45</guid>
      <comments>https://zeroone.tistory.com/45#entry45comment</comments>
      <pubDate>Sun, 3 Apr 2022 22:57:43 +0900</pubDate>
    </item>
    <item>
      <title>컴포넌트 스캔</title>
      <link>https://zeroone.tistory.com/44</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링은 자바코드의 @Bean이나 XML의 &amp;lt;bean&amp;gt; 같은 설정 정보가 없어도 자동으로 스프링 빈을 등록하는 @ComponentScan이라는 기능을 제공한다.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또, 의존관계도 자동으로 주입하는 @Autowired라는 기능도 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648909616423&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core;
    
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import static org.springframework.context.annotation.ComponentScan.*;

@Configuration
@ComponentScan(
        excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = Configuration.class))
public class AutoAppConfig {

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@ComponentScan은 @Component애노테이션이 붙은 클래스를 스캔해서 스프링 빈으로 등록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로, @Component를 상속(스프링이 지원하는 기능)받는 @Configuration과 같은 애노테션이 붙은 클래스도 같이 등록된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1648909787750&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Component
public class MemberServiceImpl implements MemberService {
	private final MemberRepository memberRepository;
    @Autowired
    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Autowired &lt;/span&gt;&lt;span&gt;는 의존관계를 자동으로 주입해준다 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컴포넌트 스캔과 자동 의존관계 주입 동작 단계&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. @ComponentScan&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;@ComponentScan 은 @Component 가 붙은 모든 클래스를 스프링 빈으로 등록한다.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;이때 스프링 빈의 기본 이름은 클래스명을 사용하되 맨 앞글자만 소문자를 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빈 이름 기본 전략: MemberServiceImpl 클래스 memberServiceImpl&lt;/li&gt;
&lt;li&gt;빈 이름 직접 지정: 만약 스프링 빈의 이름을 직접 지정하고 싶으면 @Component(&quot;memberService2&quot;) 이런식으로 이름을 부여하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DRxVi/btrye344rZz/IadcS53ouCeVueFWUtFXrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DRxVi/btrye344rZz/IadcS53ouCeVueFWUtFXrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DRxVi/btrye344rZz/IadcS53ouCeVueFWUtFXrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDRxVi%2Fbtrye344rZz%2FIadcS53ouCeVueFWUtFXrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;272&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;2. @Autowired &lt;/span&gt;&lt;span&gt;의존관계 자동 주입&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자에 @Autowired 를 지정하면, 스프링 컨테이너가 자동으로 해당 스프링 빈을 찾아서 주입한다.&lt;/li&gt;
&lt;li&gt;이때 기본 조회 전략은 타입이 같은 빈을 찾아서 주입한다.&lt;/li&gt;
&lt;li&gt;getBean(MemberRepository.class) 와 동일하다고 이해하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3e78l/btryjGgg9HD/Ke2ldYSFcQonMBmEyHsHQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3e78l/btryjGgg9HD/Ke2ldYSFcQonMBmEyHsHQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3e78l/btryjGgg9HD/Ke2ldYSFcQonMBmEyHsHQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3e78l%2FbtryjGgg9HD%2FKe2ldYSFcQonMBmEyHsHQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;264&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자에 파라미터가 많아도 다 찾아서 자동으로 주입한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHSHrE/btryjF2Jw8S/YoNhdiebyRgAwBAws0Z3XK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHSHrE/btryjF2Jw8S/YoNhdiebyRgAwBAws0Z3XK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHSHrE/btryjF2Jw8S/YoNhdiebyRgAwBAws0Z3XK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHSHrE%2FbtryjF2Jw8S%2FYoNhdiebyRgAwBAws0Z3XK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;264&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;탐색 위치와 기본 스캔 대상&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;탐색할 패키지의 시작 위치 지정 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1648911054522&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ComponentScan(
          basePackages = &quot;hello.core&quot;, &quot;hello.service&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;basePackages = {&quot;hello.core&quot;, &quot;hello.service&quot;} 이렇게 여러 시작 위치를 지정할 수도 있다.&lt;/li&gt;
&lt;li&gt;만약 지정하지 않으면 &lt;span style=&quot;color: #242424;&quot;&gt;@ComponentScan &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;이 붙은 설정 정보 클래스의 패키지가 시작 위치가 된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;권장하는 방법 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개인적으로 즐겨 사용하는 방법은 패키지 위치를 지정하지 않고, 설정 정보 클래스의 위치를 프로젝트 최상단에 두는 것이다. 최근 스프링 부트도 이 방법을 기본으로 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;컴포넌트 스캔 기본 대상&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Component : 컴포넌트 스캔에서 사용&lt;/li&gt;
&lt;li&gt;@Controlller : 스프링 MVC 컨트롤러에서 사용, 스프링 MVC 컨트롤러로 인식&lt;/li&gt;
&lt;li&gt;@Service : 스프링 비즈니스 로직에서 사용, 특별한 처리 없음, 개발자들이 핵심 비즈니스 로직이 여기 있껬구나 인식하는데 도움&lt;/li&gt;
&lt;li&gt;@Repository &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;스프링 데이터 접근 계층에서 사용, 스프링 데이터 접근 계층으로 인식하고 데이터 계층의 예외를 스프링 예외로 변환&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;@Configuration : 스프링 설정 정보에서 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필터&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;useDefaultFilters : 옵션은 기본으로 켜져있는데, 이 옵션을 끄면 기본 스캔 대상들이 제외된다.&lt;/li&gt;
&lt;li&gt;includeFilters : 컴포넌트 스캔 대상을 추가로 지정한다.&lt;/li&gt;
&lt;li&gt;excludeFilters : 컴포넌트 스캔에서 제외할 대상을 지정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1648973674358&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; @ComponentScan(
    includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class),
    excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class)
  )&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FilterType&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ANNOTATION: 기본값, 애노테이션을 인식해서 동작한다.&lt;br /&gt;ex) org.example.SomeAnnotation&lt;/li&gt;
&lt;li&gt;ASSIGNABLE_TYPE: 지정한 타입과 자식 타입을 인식해서 동작한다.&lt;br /&gt;ex) org.example.SomeClass&lt;/li&gt;
&lt;li&gt;ASPECTJ: AspectJ 패턴 사용&lt;br /&gt;ex) org.example..*Service+&lt;/li&gt;
&lt;li&gt;REGEX: 정규 표현식&lt;br /&gt;ex) org\.example\.Default.*&lt;/li&gt;
&lt;li&gt;CUSTOM: TypeFilter 이라는 인터페이스를 구현해서 처리&lt;br /&gt;ex) org.example.MyTypeFilter&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;중복 등록과 충돌 &lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컴포넌트 스캔에서 같은 빈 이름을 등록하면 어떻게 될까&lt;/span&gt;&lt;span&gt;? &lt;/span&gt;&lt;span&gt;다음 두가지 상황이 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;자동 빈 등록 &lt;/span&gt;&lt;span&gt;vs &lt;/span&gt;&lt;span&gt;&lt;span&gt;자동 빈 등록&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;컴포넌트 스캔에 의해 자동으로 스프링 빈이 등록되는데&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;그 이름이 같은 경우 스프링은 오류를 발생시킨다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;ConflictingBeanDefinitionException&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;예외 발생&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;수동 빈 등록 &lt;/span&gt;&lt;span&gt;vs &lt;/span&gt;&lt;span&gt;자동 빈 등록&lt;br /&gt;수동 빈 우선권 (스프링은 명시적인 것을 우선하는 경향이 있다) -&amp;gt; 최근에는 스프링 부트 에러 발생시킨다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Spring/core</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/44</guid>
      <comments>https://zeroone.tistory.com/44#entry44comment</comments>
      <pubDate>Sun, 3 Apr 2022 19:02:25 +0900</pubDate>
    </item>
    <item>
      <title>싱글톤 컨테이너</title>
      <link>https://zeroone.tistory.com/43</link>
      <description>&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;순수 자바를 이용한 AppConfig의 문제점&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;우리가 만들었던 스프링 없는 순수한 &lt;/span&gt;&lt;span&gt;DI &lt;/span&gt;&lt;span&gt;컨테이너인 &lt;/span&gt;&lt;span&gt;AppConfig&lt;/span&gt;&lt;span&gt;는 요청을 할 때 마다 객체를 새로 생성한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;고객 트래픽이 초당 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;이 나오면 초당 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;개 객체가 생성되고 소멸된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;!&amp;nbsp; 메모리 낭비가 심하다.&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;해결방안은 해당 객체가 딱 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;개만 생성되고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;공유하도록 설계하면 된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&amp;nbsp; =&amp;gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;싱글톤 패턴&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;싱글톤 패턴&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클래스의 인스턴스가 딱 &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;개만 생성되는 것을 보장하는 디자인 패턴이다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그래서 객체 인스턴스를 &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;개 이상 생성하지 못하도록 막아야 한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; - private &lt;/span&gt;&lt;span&gt;생성자를 사용해서 외부에서 임의로 &lt;/span&gt;&lt;span&gt;new &lt;/span&gt;&lt;span&gt;키워드를 사용하지 못하도록 막아야 한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;pre id=&quot;code_1648896777815&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.singleton;

public class SingletonService {
	//1. static 영역에 객체를 딱 1개만 생성해둔다.
	private static final SingletonService instance = new SingletonService();
	
    //2. public으로 열어서 객체 인스터스가 필요하면 이 static 메서드를 통해서만 조회하도록 허용한다.
    public static SingletonService getInstance() {
    	return instance;
	}
  	//3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다. 
    private SingletonService() {
	}
	public void logic() { System.out.println(&quot;싱글톤 객체 로직 호출&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;싱글톤 패턴 문제점 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.&lt;/li&gt;
&lt;li&gt;의존관계상 클라이언트가 구체 클래스에 의존한다.&lt;/li&gt;
&lt;li&gt;DIP를 위반한다.&lt;/li&gt;
&lt;li&gt;클라이언트가 구체 클래스에 의존해서 OCP 원칙을 위반할 가능성이 높다.&lt;/li&gt;
&lt;li&gt;테스트하기 어렵다.&lt;/li&gt;
&lt;li&gt;내부 속성을 변경하거나 초기화 하기 어렵다.&lt;/li&gt;
&lt;li&gt;private 생성자로 자식 클래스를 만들기 어렵다.&lt;/li&gt;
&lt;li&gt;결론적으로 유연성이 떨어진다.&lt;/li&gt;
&lt;li&gt;안티패턴으로 불리기도 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글톤 컨테이너&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 컨테이너는 싱글톤 패턴의 문제점을 해결하면서, 객체 인스턴스를 싱글톤(1개만 생성)으로 관리한다.&lt;/li&gt;
&lt;li&gt;스프링 컨테이너는 싱글턴 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리한다.&lt;/li&gt;
&lt;li&gt;스프링 컨테이너는 싱글톤 컨테이너 역할을 한다. 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라 한다.&lt;/li&gt;
&lt;li&gt;스프링 컨테이너의 이런 기능 덕분에 싱글턴 패턴의 모든 단점을 해결하면서 객체를 싱글톤으로 유지할 수 있다.&lt;/li&gt;
&lt;li&gt;싱글톤 패턴을 위한 지저분한 코드가 들어가지 않아도 된다.&lt;/li&gt;
&lt;li&gt;DIP, OCP, 테스트, private 생성자로 부터 자유롭게 싱글톤을 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;싱글톤 방식의 주의점 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;싱글톤 패턴이든&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;스프링 같은 싱글톤 컨테이너를 사용하든&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;객체 인스턴스를 하나만 생성해서 공유하는 싱글톤 방식은 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 상태를 유지&lt;/span&gt;&lt;span&gt;(stateful)&lt;/span&gt;&lt;span&gt;하게 설계하면 안된다&lt;/span&gt;&lt;span&gt;. 즉, &lt;/span&gt;&lt;span&gt;무상태&lt;/span&gt;&lt;span&gt;(stateless)&lt;/span&gt;&lt;span&gt;로 설계해야 한다!&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 클라이언트에 의존적인 필드가 있으면 안된다.&lt;/li&gt;
&lt;li&gt;특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다!&lt;/li&gt;
&lt;li&gt;가급적 읽기만 가능해야 한다.&lt;/li&gt;
&lt;li&gt;필드 대신에 자바에서 공유되지 않는, 지역변수, 파라미터 ThreadLocal 등을 사용해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링 빈의 필드에 공유 값을 설정하면 정말 큰 장애가 발생할 수 있다&lt;/span&gt;&lt;span&gt;!!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그럼에도 불가피하게 사용해야 될 경우는? 옵션을 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;@Configuration&lt;/span&gt;&lt;span&gt;과 싱글톤&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648907426128&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; @Configuration
  public class AppConfig {
      @Bean
      public MemberService memberService() {
          return new MemberServiceImpl(memberRepository());
      }
      @Bean
      public OrderService orderService() {
          return new OrderServiceImpl(
                  memberRepository(),
                  discountPolicy());
}
      @Bean
      public MemberRepository memberRepository() {
          return new MemoryMemberRepository();
      }
... }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;memberService &lt;/span&gt;&lt;span&gt;빈을 만드는 코드를 보면 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;memberRepository() &lt;/span&gt;&lt;span&gt;를 호출한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;이 메서드를 호출하면 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;new MemoryMemberRepository() &lt;/span&gt;&lt;span&gt;를 호출한다&lt;/span&gt;&lt;span&gt;. orderService &lt;/span&gt;&lt;span&gt;빈을 만드는 코드도 동일하게 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;memberRepository() &lt;/span&gt;&lt;span&gt;를 호출한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;이 메서드를 호출하면 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;new MemoryMemberRepository() &lt;/span&gt;&lt;span&gt;를 호출한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결과적으로 각각 다른 &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;개의 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;MemoryMemberRepository &lt;/span&gt;&lt;span&gt;가 생성되면서 싱글톤이 깨지는 것 처럼 보인다&lt;/span&gt;&lt;span&gt;. 아무리 스프링 컨테이너라지만 자바의 문법을 바꿀 순 없다. &lt;/span&gt;&lt;span&gt;스프링 컨테이너는 이 문제를 어떻게 해결할까&lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;@Configuration&lt;/span&gt;&lt;span&gt;과 바이트코드 조작의 마법 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링은 클래스의 바이트코드를 조작하는 라이브러리를 사용한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;모든 비밀은 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;@Configuration &lt;/span&gt;&lt;span&gt;을 적용한 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;AppConfig &lt;/span&gt;&lt;span&gt;에 있다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;사실 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;AnnotationConfigApplicationContext &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;에 파라미터로 넘긴 값은 스프링 빈으로 등록된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;그래서 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;AppConfig &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;도 스프링 빈이 된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;AppConfig &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;스프링 빈을 조회해서 클래스 정보를 출력해보자&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648908625027&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test
void configurationDeep() {
    ApplicationContext ac = new
	AnnotationConfigApplicationContext(AppConfig.class);
	
    //AppConfig도 스프링 빈으로 등록된다.
	AppConfig bean = ac.getBean(AppConfig.class);
	
    System.out.println(&quot;bean = &quot; + bean.getClass());
    //출력: bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd479d70
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;순수한 클래스라면 다음과 같이 출력되어야 한다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;&amp;nbsp;// class hello.core.AppConfig &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그런데 예상과는 다르게 클래스 명에 &lt;/span&gt;&lt;span&gt;xxxCGLIB&lt;/span&gt;&lt;span&gt;가 붙으면서 상당히 복잡해진 것을 볼 수 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;이것은 내가 만든 클래스가 아니라 스프링이 &lt;/span&gt;&lt;span&gt;CGLIB&lt;/span&gt;&lt;span&gt;라는 바이트코드 조작 라이브러리를 사용해서 &lt;/span&gt;&lt;span&gt;AppConfig &lt;/span&gt;&lt;span&gt;클래스를 상속받은 임의의 다른 클래스를 만들고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;그 다른 클래스를 스프링 빈으로 등록한 것이다&lt;/span&gt;&lt;span&gt;! &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t3dV3/btrycC07o62/wquiS5OSNOfFm5Ft73DMT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t3dV3/btrycC07o62/wquiS5OSNOfFm5Ft73DMT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t3dV3/btrycC07o62/wquiS5OSNOfFm5Ft73DMT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft3dV3%2FbtrycC07o62%2FwquiS5OSNOfFm5Ft73DMT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;315&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AppConfig@CGLIB 예상 코드&lt;/p&gt;
&lt;pre id=&quot;code_1648908815251&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Bean
public MemberRepository memberRepository() {
    if (memoryMemberRepository가 이미 스프링 컨테이너에 등록되어 있으면?) { 
    	return 스프링 컨테이너에서 찾아서 반환;
	} else { //스프링 컨테이너에 없으면
		기존 로직을 호출해서 MemoryMemberRepository를 생성하고 스프링 컨테이너에 등록 return 반환
	} 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Configuration이 없으면 싱글톤 보장하지 않는다!&lt;/p&gt;</description>
      <category>Spring/core</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/43</guid>
      <comments>https://zeroone.tistory.com/43#entry43comment</comments>
      <pubDate>Sat, 2 Apr 2022 23:15:20 +0900</pubDate>
    </item>
    <item>
      <title>스프링 컨테이너와 스프링 빈</title>
      <link>https://zeroone.tistory.com/42</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 컨테이너의 생성 과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 스프링 컨테이너 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 구성정보(AppConfig.class) 지정이 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGbuiM/btryg3XeLI2/z4m8G4Glny1kQv5oMwOXq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGbuiM/btryg3XeLI2/z4m8G4Glny1kQv5oMwOXq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGbuiM/btryg3XeLI2/z4m8G4Glny1kQv5oMwOXq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGbuiM%2Fbtryg3XeLI2%2Fz4m8G4Glny1kQv5oMwOXq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;285&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 스프링 빈 등록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 빈 이름은 메서드 이름을 사용한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 빈 이름을 직접 부여할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 생성자 주입의 경우 객체를 만들어야 하므로, 이 단계에서 주입이된다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;주의&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;빈&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;이름은&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;항상&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;다른&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;이름을&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;부여&lt;/b&gt;해야&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;같은&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;이름을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;부여하면&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;다른&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;빈이&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;무시되거나&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;기존&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;빈을&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;덮어버리거나&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;설정에&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;따라&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;오류가&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;발생한다&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xHuRY/btrydIUwKA7/AKyDTza7HlAq0ejAZE43ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xHuRY/btrydIUwKA7/AKyDTza7HlAq0ejAZE43ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xHuRY/btrydIUwKA7/AKyDTza7HlAq0ejAZE43ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxHuRY%2FbtrydIUwKA7%2FAKyDTza7HlAq0ejAZE43ak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;272&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 스프링 빈 의존관계 설정 - 준비&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rpBNU/btrye3DB0MA/HfKbXj2I37wGKIxofhxj3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rpBNU/btrye3DB0MA/HfKbXj2I37wGKIxofhxj3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rpBNU/btrye3DB0MA/HfKbXj2I37wGKIxofhxj3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrpBNU%2Fbtrye3DB0MA%2FHfKbXj2I37wGKIxofhxj3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;272&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 스프링 빈 의존관계 설정 - 완료&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/comh7t/btryhOldK8R/TwY64ffruoqSxCwUBK2kMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/comh7t/btryhOldK8R/TwY64ffruoqSxCwUBK2kMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/comh7t/btryhOldK8R/TwY64ffruoqSxCwUBK2kMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcomh7t%2FbtryhOldK8R%2FTwY64ffruoqSxCwUBK2kMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;272&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링 컨테이너는 설정 정보를 참고해서 의존관계를 주입&lt;/span&gt;&lt;span&gt;(DI)&lt;/span&gt;&lt;span&gt;한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;싱글톤 방식&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;스프링 빈 조회 - 기본&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ac.getBean(빈이름, 타입)&lt;/li&gt;
&lt;li&gt;ac.getBean(타입)&lt;/li&gt;
&lt;li&gt;조회 대상 스프링 빈이 없으면 예외 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;     NoSuchBeanDefinitionException: No bean named 'xxxxx' available
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;스프링 빈 조회 &lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;동일한 타입이 둘 이상 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입으로 조회시 같은 타입의 스프링 빈이 둘 이상이면 오류가 발생한다. 이때는 빈 이름을 지정하자.&lt;/li&gt;
&lt;li&gt;ac.getBeansOfType() 을 사용하면 해당 타입의 모든 빈을 조회할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;스프링 빈 조회 &lt;/span&gt;&lt;span&gt;- &lt;/span&gt;&lt;span&gt;상속 관계&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모 타입으로 조회하면, 자식 타입도 함께 조회한다.&lt;/li&gt;
&lt;li&gt;그래서 모든 자바 객체의 최고 부모인 Object 타입으로 조회하면, 모든 스프링 빈을 조회한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;BeanFactory&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;와 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;ApplicationContext&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;644&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cY7011/btryf0NwrLb/pRYWAz4G2Yal7kb2SgLOKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cY7011/btryf0NwrLb/pRYWAz4G2Yal7kb2SgLOKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cY7011/btryf0NwrLb/pRYWAz4G2Yal7kb2SgLOKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcY7011%2Fbtryf0NwrLb%2FpRYWAz4G2Yal7kb2SgLOKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;212&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;644&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;BeanFactory &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 컨테이너의 최상위 인터페이스다.&lt;/li&gt;
&lt;li&gt;스프링 빈을 관리하고 조회하는 역할을 담당한다.&lt;/li&gt;
&lt;li&gt;getBean() 을 제공한다.&lt;/li&gt;
&lt;li&gt;지금까지 우리가 사용했던 대부분의 기능은 BeanFactory가 제공하는 기능이다&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ApplicatonContext&lt;/span&gt;&lt;span&gt;가 제공하는 부가기능&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oLlvC/btryguOmS77/EQQKXzMhGK7t1qHXGNktx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oLlvC/btryguOmS77/EQQKXzMhGK7t1qHXGNktx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oLlvC/btryguOmS77/EQQKXzMhGK7t1qHXGNktx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoLlvC%2FbtryguOmS77%2FEQQKXzMhGK7t1qHXGNktx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;544&quot; height=&quot;189&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지소스를 활용한 국제화 기능 &lt;br /&gt;예를 들어서 한국에서 들어오면 한국어로, 영어권에서 들어오면 영어로 출력&lt;/li&gt;
&lt;li&gt;환경변수 &lt;br /&gt;로컬, 개발, 운영등을 구분해서 처리&lt;/li&gt;
&lt;li&gt;애플리케이션 이벤트 &lt;br /&gt;이벤트를 발행하고 구독하는 모델을 편리하게 지원&lt;/li&gt;
&lt;li&gt;편리한 리소스 조회 &lt;br /&gt;파일, 클래스패스, 외부 등에서 리소스를 편리하게 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정리 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ApplicationContext는 BeanFactory의 기능을 상속받는다.&lt;/li&gt;
&lt;li&gt;ApplicationContext는 빈 관리기능 + 편리한 부가 기능을 제공한다.&lt;/li&gt;
&lt;li&gt;BeanFactory를 직접 사용할 일은 거의 없다. 부가기능이 포함된 ApplicationContext를 사용한다.&lt;/li&gt;
&lt;li&gt;BeanFactory나 ApplicationContext를 스프링 컨테이너라 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;다양한 설정 형식 지원 &lt;/span&gt;&lt;span&gt;- 어노테이션 기반 자&lt;/span&gt;&lt;span&gt;바 코드&lt;/span&gt;&lt;span&gt;, XML&lt;br /&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링 컨테이너는 다양한 형식의 설정 정보를 받아드릴 수 있게 유연하게 설계되어 있다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBxE33/btryeut8ZXh/6uSQIbh0axrCZUwAiwL3oK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBxE33/btryeut8ZXh/6uSQIbh0axrCZUwAiwL3oK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBxE33/btryeut8ZXh/6uSQIbh0axrCZUwAiwL3oK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBxE33%2Fbtryeut8ZXh%2F6uSQIbh0axrCZUwAiwL3oK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;531&quot; height=&quot;313&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;XML&lt;/span&gt;&lt;span&gt;을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;사용하면&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;컴파일&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;없이&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;빈&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;설정&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;정보를&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;변경할&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;수&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;있는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;장점도&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;있으므로&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;한번쯤&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;배워두는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;것도&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;괜찮다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;스프링&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;빈&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;설정&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;메타&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;정보&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;BeanDefinition&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링은 어떻게 이런 다양한 설정 형식을 지원하는 것일까&lt;/span&gt;&lt;span&gt;? &lt;/span&gt;&lt;span&gt;그 중심에는 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;BeanDefinition &lt;/span&gt;&lt;span&gt;이라는 추상화가 있다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;쉽게 이야기해서 &lt;/span&gt;&lt;span&gt;역할과 구현을 개념적으로 나눈 것&lt;/span&gt;&lt;span&gt;이다&lt;/span&gt;&lt;span&gt;! &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XML을 읽어서 BeanDefinition을 만들면 된다.&lt;/li&gt;
&lt;li&gt;자바 코드를 읽어서 BeanDefinition을 만들면 된다.&lt;/li&gt;
&lt;li&gt;스프링 컨테이너는 자바 코드인지, XML인지 몰라도 된다. 오직 BeanDefinition만 알면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BeanDefinition 을 빈 설정 메타정보라 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Bean , &amp;lt;bean&amp;gt; 당 각각 하나씩 메타 정보가 생성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 컨테이너는 이 메타정보를 기반으로 스프링 빈을 생성한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;258&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kF3iM/btryd2kl7bi/EZ9lnZ3KV1NqZ1gwZqvvp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kF3iM/btryd2kl7bi/EZ9lnZ3KV1NqZ1gwZqvvp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kF3iM/btryd2kl7bi/EZ9lnZ3KV1NqZ1gwZqvvp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkF3iM%2Fbtryd2kl7bi%2FEZ9lnZ3KV1NqZ1gwZqvvp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;550&quot; height=&quot;156&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;258&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드레벨&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/v3gMC/btrydJlFNag/VGSfs6Vo6K1uKNs9qBghq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/v3gMC/btrydJlFNag/VGSfs6Vo6K1uKNs9qBghq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/v3gMC/btrydJlFNag/VGSfs6Vo6K1uKNs9qBghq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fv3gMC%2FbtrydJlFNag%2FVGSfs6Vo6K1uKNs9qBghq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;562&quot; height=&quot;304&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AnnotationConfigApplicationContext 는 AnnotatedBeanDefinitionReader 를 사용해서 AppConfig.class 를 읽고 BeanDefinition 을 생성한다.&lt;/li&gt;
&lt;li&gt;GenericXmlApplicationContext 는 XmlBeanDefinitionReader 를 사용해서 appConfig.xml 설정 정보를 읽고 BeanDefinition 을 생성한다.&lt;/li&gt;
&lt;li&gt;새로운 형식의 설정 정보가 추가되면, XxxBeanDefinitionReader를 만들어서 BeanDefinition 을 생성하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BeanDefinition 정보&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;BeanClassName: 생성할 빈의 클래스 명(자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음)&lt;/li&gt;
&lt;li&gt;factoryBeanName: 팩토리 역할의 빈을 사용할 경우 이름, 예) appConfig&lt;/li&gt;
&lt;li&gt;factoryMethodName: 빈을 생성할 팩토리 메서드 지정, 예) memberService&lt;/li&gt;
&lt;li&gt;Scope: 싱글톤(기본값)&lt;/li&gt;
&lt;li&gt;lazyInit: 스프링 컨테이너를 생성할 때 빈을 생성하는 것이 아니라, 실제 빈을 사용할 때 까지 최대한 생성을 지연처리 하는지 여부&lt;/li&gt;
&lt;li&gt;InitMethodName: 빈을 생성하고, 의존관계를 적용한 뒤에 호출되는 초기화 메서드 명&lt;/li&gt;
&lt;li&gt;DestroyMethodName: 빈의 생명주기가 끝나서 제거하기 직전에 호출되는 메서드 명&lt;/li&gt;
&lt;li&gt;Constructor arguments, Properties: 의존관계 주입에서 사용한다. (자바 설정 처럼 팩토리 역할의 빈을 사용하면 없음)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론 : &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;BeanDefinition&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;에 대해서는 너무 깊이있게 이해하기 보다는&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;스프링이 다양한 형태의 설정 정보를 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;BeanDefinition&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;으로 추상화해서 사용하는 것 정도만 이해하면 된다&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Spring/core</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/42</guid>
      <comments>https://zeroone.tistory.com/42#entry42comment</comments>
      <pubDate>Sat, 2 Apr 2022 19:40:07 +0900</pubDate>
    </item>
    <item>
      <title>스프링 핵심 원리 이해 - 객체 지향 원리 적용</title>
      <link>https://zeroone.tistory.com/41</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;기존의 문제점&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;client가 객체를 생성하고 연결하면 중간에 서버에서 객체에 대한 설정이 바뀔 경우 클라이언트의 소스를 같이 고쳐야한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;AppConfig &lt;/span&gt;&lt;span&gt;등장&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;애플리케이션의 전체 동작 방식을 구성&lt;/span&gt;&lt;span&gt;(config)&lt;/span&gt;&lt;span&gt;하기 위해&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;b&gt;&lt;span&gt;구현 객체를 생성&lt;/span&gt;&lt;/b&gt;&lt;span&gt;하고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;b&gt;&lt;span&gt;연결&lt;/span&gt;&lt;/b&gt;&lt;span&gt;하는 책임을 가지는 별도의 설정 클래스를 만들자&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648884924655&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core;

import hello.core.discount.FixDiscountPolicy;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;

public class AppConfig {
    public MemberService memberService() {
        return new MemberServiceImpl(new MemoryMemberRepository());
	}
    public OrderService orderService() {
    	return new OrderServiceImpl(
        	new MemoryMemberRepository(),
            	new FixDiscountPolicy());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;객체의 생성과 연결은 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;AppConfig &lt;/span&gt;&lt;span&gt;가 담당한다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;DIP &lt;/span&gt;&lt;span&gt;완성&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;MemberServiceImpl &lt;/span&gt;&lt;span&gt;은 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;MemberRepository &lt;/span&gt;&lt;span&gt;인 추상에만 의존하면 된다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;이제 구체 클래스를 몰라도 된다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;&lt;span&gt;관심사의 분리&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;객체를 생성하고 연결하는 역할과 실행하는 역할이 명확히 분리되었다&lt;/span&gt;&lt;span&gt;. MemberServicdImpl, &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;OrderServiceImpl &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;은 기능을 실행하는 책임만 지면 된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;AppConfig 리팩토링&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;중복을 제거하고&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;역할에 따른 구현이 보이도록 리팩터링 하자&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1648885227432&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
public class AppConfig {
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }
    public OrderService orderService() {
    	return new OrderServiceImpl(
                memberRepository(),
                discountPolicy());
	}
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
	}
    public DiscountPolicy discountPolicy() {
        return new FixDiscountPolicy();
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242424;&quot;&gt;new MemoryMemberRepository() &lt;/span&gt;&lt;span&gt;이 부분이 중복 제거되었다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;이제 &lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;MemoryMemberRepository &lt;/span&gt;&lt;span&gt;를 다른 구현체로 변경할 때 한 부분만 변경하면 된다&lt;/span&gt;&lt;span&gt;. &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;color: #242424;&quot;&gt;AppConfig &lt;/span&gt;&lt;span&gt;를 보면 역할과 구현 클래스가 한눈에 들어온다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;애플리케이션 전체 구성이 어떻게 되어있는지 빠르게 파악할 수 있다 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;결론 : AppConfig&lt;/span&gt;&lt;span&gt;의 등장으로 애플리케이션이 크게 사용 영역과&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;객체를 생성하고 구성&lt;/span&gt;&lt;span&gt;(Configuration)&lt;/span&gt;&lt;span&gt;하는 영역으로 분리되었다&lt;/span&gt;&lt;span&gt;.&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; SRP, DIP, OCP 적용.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;IoC, DI, &lt;/span&gt;&lt;span&gt;그리고 컨테이너&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;IoC(Inversion of Control) : 프로그램의 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 제어의 역전&lt;/span&gt;&lt;span&gt;(IoC)&lt;/span&gt;&lt;span&gt;이라 한다.&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프레임워크 vs 라이브러리&lt;br /&gt;프레임워크가 내가 작성한 코드를 제어하고, 대신 실행하면 그것은 프레임워크가 맞다. (JUnit)&lt;br /&gt;반면에 내가 작성한 코드가 직접 제어의 흐름을 담당한다면 그것은 프레임워크가 아니라 라이브러리다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;의존관계 주입 &lt;/span&gt;&lt;span&gt;DI(Dependency Injection)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적인 클래스 의존 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XqGCa/btryd9qPiTq/fUtMMCQW6LYZzHdZar0v8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XqGCa/btryd9qPiTq/fUtMMCQW6LYZzHdZar0v8K/img.png&quot; data-alt=&quot;클래스 다이어그램&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XqGCa/btryd9qPiTq/fUtMMCQW6LYZzHdZar0v8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXqGCa%2Fbtryd9qPiTq%2FfUtMMCQW6LYZzHdZar0v8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;502&quot; height=&quot;351&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;클래스 다이어그램&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 시점에 결정되는 동적인 객체(인스턴스) 의존 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HIB7n/btryg4Iz8fD/pxouUBDiQ4obCaNwitzS8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HIB7n/btryg4Iz8fD/pxouUBDiQ4obCaNwitzS8K/img.png&quot; data-alt=&quot;객체 다이어그램&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HIB7n/btryg4Iz8fD/pxouUBDiQ4obCaNwitzS8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHIB7n%2Fbtryg4Iz8fD%2FpxouUBDiQ4obCaNwitzS8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;152&quot; data-origin-width=&quot;910&quot; data-origin-height=&quot;276&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;객체 다이어그램&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;AppConfig&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;처럼&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;객체를&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;생성하고&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;관리하면서&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;의존관계를&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;연결해&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;주는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;것을&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;IoC&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;컨테이너&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;또는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;b&gt;DI&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt; &lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;컨테이너&lt;/b&gt;&lt;/span&gt;&lt;span&gt;라&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;한다&lt;/span&gt;&lt;span&gt;. (어셈블러, 오브젝트 팩토리)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;App&lt;/span&gt;&lt;span&gt;C&lt;/span&gt;&lt;span&gt;onfig&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;스프링&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;기반으로&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;변경&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1648887292778&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core;

import hello.core.discount.DiscountPolicy;
import hello.core.discount.RateDiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration

public class AppConfig {
	@Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }
    
    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(
                memberRepository(),
                discountPolicy());
    }
    
    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    
	@Bean       
    public DiscountPolicy discountPolicy() {
          return new RateDiscountPolicy();
	} 
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;App&lt;/span&gt;&lt;span&gt;Config&lt;/span&gt;&lt;span&gt;에&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;설정을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;구성한다는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;뜻의&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@Configurati&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;붙여준다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;메서드에&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;@Bean&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;붙여준다&lt;/span&gt;&lt;span&gt;. &lt;/span&gt;&lt;span&gt;이렇게&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;하면&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;스프링&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;컨테이너에&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;스프링&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;빈으로&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;등록한다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1648887386494&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//        AppConfig appConfig = new AppConfig();
//        MemberService memberService = appConfig.memberService();

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
MemberService memberService = applicationContext.getBean(&quot;memberService&quot;, MemberService.class);​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순수 java 코드에서 선언한 AppConfig 대신 스프링 컨테이너를 적용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;스프링 컨테이너 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ApplicationContext 를 스프링 컨테이너라 한다.&lt;/li&gt;
&lt;li&gt;스프링 컨테이너는 @Configuration 이 붙은 AppConfig 를 설정(구성) 정보로 사용한다. 여기서 @Bean 이라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다. 이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈이라 한다.&lt;/li&gt;
&lt;li&gt;스프링 빈은 @Bean 이 붙은 메서드의 명을 스프링 빈의 이름으로 사용한다. ( memberService , orderService )&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</description>
      <category>Spring/core</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/41</guid>
      <comments>https://zeroone.tistory.com/41#entry41comment</comments>
      <pubDate>Sat, 2 Apr 2022 17:20:00 +0900</pubDate>
    </item>
    <item>
      <title>HTTP 헤더1 - 일반 헤더</title>
      <link>https://zeroone.tistory.com/40</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;HTTP 헤더&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;header-field = field-name &quot;:&quot; OWS field-value OWS (OWS:띄어쓰기 허용)&lt;/li&gt;
&lt;li&gt;field-name은 대소문자 구문 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;헤더 분류&lt;/h3&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Request 헤더: 요청 정보, 예) User-Agent: Mozilla/5.0 (Macintosh; ..)&lt;/li&gt;
&lt;li&gt;Response 헤더: 응답 정보, 예) Server: Apache&lt;/li&gt;
&lt;li&gt;General&amp;nbsp;헤더:&amp;nbsp;메시지 전체에 적용되는 정보,&amp;nbsp;예) Connection: close&lt;/li&gt;
&lt;li&gt;Entity 헤더: 엔티티 바디 정보, 예) Content-Type: text/html, Content-Length: 3423&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;HTTP 표준 변경&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1999년 RFC2616 (폐기) -&amp;gt; 2014년 RFC7230~7235 등장&lt;/li&gt;
&lt;li&gt;엔티티&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(Entity) -&amp;gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;표현&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(Representation)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Representation = representation Metadata + Representation Data&lt;/li&gt;
&lt;li&gt;표현 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;= &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;표현 메타데이터 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;+ &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;표현 데이터&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;HTTP BODY&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지바디 = payload&lt;/li&gt;
&lt;li&gt;표현은 요청이나 응답에서 전달할 실제 데이터&lt;/li&gt;
&lt;li&gt;표현 헤더는 표현 데이터를 해석할 수 있는 정보 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;표현 헤더&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Content-Type: 표현 데이터의 형식&lt;/li&gt;
&lt;li&gt;Content-Encoding: 표현 데이터의 압축 방식&lt;/li&gt;
&lt;li&gt;Content-Language: 표현 데이터의 자연 언어&lt;/li&gt;
&lt;li&gt;Content-Length: 표현 데이터의 길이&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;표현 헤더는 전송&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;응답 둘다 사용&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;협상(컨텐츠 네고시에이션)&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Accept: 클라이언트가 선호하는 미디어 타입 전달&lt;/li&gt;
&lt;li&gt;Accept-Charset: 클라이언트가 선호하는 문자 인코딩&lt;/li&gt;
&lt;li&gt;Accept-Encoding: 클라이언트가 선호하는 압축 인코딩&lt;/li&gt;
&lt;li&gt;Accept-Language: 클라이언트가 선호하는 자연 언어&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;협상 헤더는 요청시에만 사용&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;협상과 우선순위&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp;Quality Values(q)&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0~1, 클수록 높은 우선순위, 생략하면 1&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;ko-KR;q=1 (q생략)&lt;/li&gt;
&lt;li&gt;ko;q=0.9&lt;/li&gt;
&lt;li&gt;en-US;q=0.8&lt;/li&gt;
&lt;li&gt;en:q=0.7 &lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구체적인 것이 우선한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Accept: &lt;/span&gt;&lt;span&gt;text/*&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;text/plain&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;text/plain;format=flowed&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;*/* &lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;text/plain;format=flowed&lt;/li&gt;
&lt;li&gt;text/plain&lt;/li&gt;
&lt;li&gt;text/*&lt;/li&gt;
&lt;li&gt;*/*&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구체적인 것을 기준으로 미디어 타입을 맞춘다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 37.7907%; height: 234px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;Media Type&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;Quality&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;text/html;level=1 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;text/plain&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;0.3&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;image/jpeg&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;&lt;span&gt;0.5&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;text/html;level=2&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;0.4&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;text/html;level=3&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;0.7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;text/html;level=1 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;0.7&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전송 방식&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순 전송&amp;nbsp; &amp;nbsp; &amp;nbsp; | Content-Length: 3423&lt;/li&gt;
&lt;li&gt;압축 전송.&amp;nbsp; &amp;nbsp; &amp;nbsp;| Content-Encoding: gzip&lt;/li&gt;
&lt;li&gt;분할 전송.&amp;nbsp; &amp;nbsp; &amp;nbsp;| Transfer-Encoding: chunked&lt;/li&gt;
&lt;li&gt;범위 전송.&amp;nbsp; &amp;nbsp; &amp;nbsp;Range:bytes=1001-2000| Content-Range: bytes 1001-2000 / 2000(끝길이)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;일반 정보 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;From: &lt;/span&gt;&lt;span&gt;유저 에이전트의 이메일 정보&lt;br /&gt;&lt;/span&gt;&lt;span&gt;Referer: &lt;/span&gt;&lt;span&gt;이전 웹 페이지 주소 (referrer의 오타)&lt;br /&gt;&lt;/span&gt;&lt;span&gt;User-Agent: &lt;/span&gt;&lt;span&gt;유저 에이전트 애플리케이션 정보&lt;br /&gt;&lt;/span&gt;&lt;span&gt;Server: &lt;/span&gt;&lt;span&gt;요청을 처리하는 오리진 서버의 소프트웨어 정보 &lt;/span&gt;&lt;span&gt;Date: &lt;/span&gt;&lt;span&gt;메시지가 생성된 날짜&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;특별한 정보 &lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Host: 요청한 호스트 정보(도메인)&lt;/li&gt;
&lt;li&gt;Location: 페이지 리다이렉션 &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;201 (Created): Location 값은 요청에 의해 생성된 리소스 URI&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;3xx (Redirection): Location &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;값은 요청을 자동으로 리디렉션하기 위한 대상 리소스를 가리킴 &lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;-&amp;gt; 해당 Location으로 자동 이동&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Allow: &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;허용 가능한 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;HTTP &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;메서드&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;405 (Method Not Allowed) &lt;/span&gt;&lt;span&gt;에서 응답에 포함해야함 &lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ex) Allow: GET, HEAD, PUT &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Retry-After: &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;유저 에이전트가 다음 요청을 하기까지 기다려야 하는 시간&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;503 (Service Unavailable): &lt;/span&gt;&lt;span&gt;서비스가 언제까지 불능인지 알려줄 수 있음 &lt;br /&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Retry-After: Fri, 31 Dec 1999 23:59:59 GMT (&lt;/span&gt;&lt;span&gt;날짜 표기&lt;/span&gt;&lt;span&gt;) &lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Retry-After: 120 (&lt;/span&gt;&lt;span&gt;초단위 표기&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인증&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Authorization: 클라이언트 인증 정보를 서버에 전달&lt;/li&gt;
&lt;li&gt;WWW-Authenticate: 리소스 접근시 필요한 인증 방법 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;쿠키&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) set-cookie: sessionId=abcde1234; expires=Sat, 26-Dec-2020 00:00:00 GMT; path=/; domain=.google.com; Secure&lt;/li&gt;
&lt;li&gt;사용처&lt;br /&gt;- 사용자 로그인 세션 관리&lt;br /&gt;- 광고 정보 트래킹&lt;/li&gt;
&lt;li&gt;쿠키 정보는 항상 서버에 전송됨&lt;br /&gt;- 네트워크 트래픽 추가 유발&lt;br /&gt;- 최소한의 정보만 사용&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;세션&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;id,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;인증 토큰&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;)&lt;br /&gt;&lt;/span&gt;- 서버에 전송하지 않고&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;웹 브라우저 내부에 데이터를 저장하고 싶으면 웹 스토리지&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(localStorage, sessionStorage)&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;참고&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;주의&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;!&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;- 보안에 민감한 데이터는 저장하면 안됨&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;주민번호&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;신용카드 번호 등등&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;생명주기&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;- Set-Cookie: &lt;/span&gt;&lt;span&gt;expires&lt;/span&gt;&lt;span&gt;=Sat, 26-Dec-2020 04:39:21 GMT&lt;br /&gt;&lt;/span&gt;- Set-Cookie: &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;max-age&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;=3600 (3600&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;초&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;), 0이나 -1일 경우 즉시 삭제&lt;br /&gt;&lt;/span&gt;- 세션 쿠키&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;만료 날짜를 생략하면 브라우저 종료시 까지만 유지&lt;br /&gt;&lt;/span&gt;- 영속 쿠키&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;만료 날짜를 입력하면 해당 날짜까지 유지&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;도메인&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;span&gt;- 명시&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;명시한 문서 기준 도메인 &lt;/span&gt;&lt;span&gt;+ &lt;/span&gt;&lt;span&gt;서브 도메인 포함&lt;br /&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp;domain=example.org&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;를 지정해서 쿠키 생성시, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;example.org&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;는 물론이고 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;dev.example.org&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;도 쿠키 접근&lt;br /&gt;&lt;/span&gt;- 생략&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;현재 문서 기준 도메인만 적용&lt;br /&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp;example.org&amp;nbsp;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;에서 쿠키를 생성하고&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;domain&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;지정을 생략시, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;example.org &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;에서만 쿠키 접근, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;dev.example.org&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;는 쿠키 미접근&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;경로&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;- 이 경로를 포함한 하위 경로 페이지만 쿠키 접근&lt;br /&gt;&lt;/span&gt;- 일반적으로 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;path=/ &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;루트로 지정&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;보안&lt;br /&gt;&lt;/span&gt;1) Secure&lt;br /&gt;&amp;nbsp; &amp;nbsp;- 쿠키는 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;http, https&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;를 구분하지 않고 전송&lt;br /&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp;- Secure&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;를 적용하면 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;https&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;인 경우에만 전송&lt;br /&gt;&lt;/span&gt;2) HttpOnly&lt;br /&gt;&amp;nbsp; &amp;nbsp;- XSS &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;공격 방지&lt;br /&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp;- 자바스크립트에서 접근 불가&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(document.cookie)&lt;br /&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp;- HTTP &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;전송에만 사용&lt;br /&gt;&lt;/span&gt;3) SameSite&lt;br /&gt;&amp;nbsp; &amp;nbsp;- XSRF &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;공격 방지&lt;br /&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp;- 요청 도메인과 쿠키에 설정된 도메인이 같은 경우만 쿠키 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>HTTP</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/40</guid>
      <comments>https://zeroone.tistory.com/40#entry40comment</comments>
      <pubDate>Sun, 13 Mar 2022 23:30:48 +0900</pubDate>
    </item>
    <item>
      <title>HTTP 상태코드</title>
      <link>https://zeroone.tistory.com/39</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;상태코드 : 클라이언트가 보낸 요청의 처리 상태를 응답에서 알려주는 기능&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1xx (Informational): 요청이 수신되어 처리중&lt;/li&gt;
&lt;li&gt;2xx (Successful): 요청 정상 처리&lt;/li&gt;
&lt;li&gt;3xx (Redirection): 요청을 완료하려면 추가 행동이 필요&lt;/li&gt;
&lt;li&gt;4xx (Client Error): 클라이언트 오류, 잘못된 문법등으로 서버가 요청을 수행할 수 없음&lt;/li&gt;
&lt;li&gt;5xx (Server Error): 서버 오류, 서버가 정상 요청을 처리하지 못함&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 인식할 수 없는 상태코드를 서버가 반환하면?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트는 상위 상태코드로 해석해서 처리 -&amp;gt; 미래에 상태 코드가 추가되어도 클라이언트 변경하지 않아도 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2xx&lt;/h3&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;200 OK.&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;요청성공 GET&lt;/li&gt;
&lt;li&gt;201 Created.&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;새로운 리소스가 생성됨&lt;/li&gt;
&lt;li&gt;202 Accepted&amp;nbsp; &amp;nbsp; 요청이 접수되었으나 처리가 완료되지 않았음. 배치처리 같은 곳에서 사용 or 1시간 뒤에 요청을 처리하는 경우&lt;/li&gt;
&lt;li&gt;204 No Content 요청을 성공적으로 수행했지만, 응답 페이로드 본문에 보낼 데이터가 없음. 웹 문서 편집기에서 save할 경우 결과&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;로 아무 내용이 없어도 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3xx&lt;/h3&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;300 Multiple Choices&lt;/li&gt;
&lt;li&gt;301 Moved Permanently&lt;/li&gt;
&lt;li&gt;302 Found&lt;/li&gt;
&lt;li&gt;303 See Other&lt;/li&gt;
&lt;li&gt;304 Not Modified&lt;/li&gt;
&lt;li&gt;307 Temporary Redirect&lt;/li&gt;
&lt;li&gt;308 Permanent Redirect&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;리다이렉트 : 웹 브라우저는 3xx 응답의 결과에 Location 헤더가 있으면, Location 위치로 자동 이동&lt;/p&gt;
&lt;img style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/pyDoD/btrvK3y8SmL/2s9Ai0kXATsCdzwQKegVS1/img.png&quot; width=&quot;400&quot; height=&quot;259&quot; data-image-src=&quot;https://blog.kakaocdn.net/dn/pyDoD/btrvK3y8SmL/2s9Ai0kXATsCdzwQKegVS1/img.png&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;2234&quot; /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영구 리다이렉션 - 특정 리소스의 URI가 영구적으로 이동, 원래의 URL 사용 X, 검색 엔진 등에서도 변경 인지&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;예) /members -&amp;gt; /users&lt;/li&gt;
&lt;li&gt;예) /event -&amp;gt; /new-event&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일시 리다이렉션 - 일시적인 변경, 따라서 검색 엔진 등에서&amp;nbsp;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;URL&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;을 변경하면 안됨&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;주문 완료 후 주문 내역 화면으로 이동&lt;/li&gt;
&lt;li&gt;PRG: Post/Redirect/Get&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특수 리다이렉션&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;결과 대신 캐시를 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영구 리다이렉션 301, 308&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;301 - 리다이렉트시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있음(MAY)&lt;/li&gt;
&lt;li&gt;308 - 리다이렉트시 요청 메서드와 본문 유지(처음 POST를 보내면 리다이렉트도 POST 유지)&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;2234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8FLsv/btrvLJBnEMf/KvqTsKp7mZFK5yG2hWUqG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8FLsv/btrvLJBnEMf/KvqTsKp7mZFK5yG2hWUqG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8FLsv/btrvLJBnEMf/KvqTsKp7mZFK5yG2hWUqG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8FLsv%2FbtrvLJBnEMf%2FKvqTsKp7mZFK5yG2hWUqG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;259&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;2234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;2234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4OdRv/btrvNIaFwZ5/aGmYTU0UlmhqWCULfgwT20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4OdRv/btrvNIaFwZ5/aGmYTU0UlmhqWCULfgwT20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4OdRv/btrvNIaFwZ5/aGmYTU0UlmhqWCULfgwT20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4OdRv%2FbtrvNIaFwZ5%2FaGmYTU0UlmhqWCULfgwT20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;2234&quot; data-origin-width=&quot;3456&quot; data-origin-height=&quot;2234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;일시적인 리다이렉션 &lt;/span&gt;&lt;span&gt;302, 307, 303&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;302 Found - 리다이렉트시 요청 메서드가 GET으로 변하고, 본문이 제거될 수 있음(MAY)&lt;/li&gt;
&lt;li&gt;307 Temporary Redirect - &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;리다이렉트시 요청 메서드와 본문 유지&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;요청 메서드를 변경하면 안된다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;. MUST NOT)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;303 See Other - &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;리다이렉트시 요청 메서드가 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;으로 변경&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;307, 303&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;을 권장하지만 현실적으로 이미 많은 애플리케이션 라이브러리들이 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;302&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;를 기본값으로 사용 &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;자동 리다이렉션시에 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;GET&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;으로 변해도 되면 그냥 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;302&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;를 사용해도 큰 문제 없음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;PRG: Post/Redirect/Get - 일시적인 리다이렉션 예시&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;주문(POST) 후 새로고침하면 재주문(POST) 되면 안된다. 이 경우는, 새로고침 시 GET으로 리다이렉트하여 결과 화면만 조회&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;기타 리다이렉션&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;300, 304&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;300 Multiple Choices: 안쓴다.&lt;/li&gt;
&lt;li&gt;304 Not Modified : 캐시를 목저으로 사용, 캐시가 수정 안되었으므로 캐시로 리다이렉트 시켜준다. (메시지 바디 포함하면 안됨).&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 조건부로 GET, HEAD 요청시 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4xx&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;400 Bad Request : 요청 구문, 메시지 등등 오류&lt;/li&gt;
&lt;li&gt;401 Unauthorized : 인증&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(Authentication): &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;본인이 누구인지 확인&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;(&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;로그인&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;) &amp;lt;-&amp;gt; &lt;/span&gt;인가&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(Authorization): &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;권한부여 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(ADMIN &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;권한처럼 특정 리소스에 접근할 수 있는 권한&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;인증이 있어야 인가가 있음&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;), 오류 메시지가 Unauthorized로 나오지만 의미는 Unauthenticted임(아쉬운부분)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;403 Forbidden : &lt;/span&gt;&lt;/span&gt;&lt;span&gt;주로 인증 자격 증명은 있지만&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;접근 권한이 불충분한 경우&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;404 Not Found : 요청 리소스가 서버에 없음 혹은 권한 부족한 클라이언트에게 특정 리소스 숨기고 싶은 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5xx&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;500 Internal Server Error : 서버 문제로 오류 발생, 애매하면 500 오류&lt;/li&gt;
&lt;li&gt;503 Service Unavailable : &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;서버가 일시적인 과부하 또는 예정된 작업으로 잠시 요청을 처리할 수 없음. &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;Retry-After &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;헤더 필드로 얼마뒤에 복구되는지 보낼 수도 있음&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>HTTP</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/39</guid>
      <comments>https://zeroone.tistory.com/39#entry39comment</comments>
      <pubDate>Sun, 13 Mar 2022 15:32:42 +0900</pubDate>
    </item>
    <item>
      <title>[ Algorithm][Template] 이진 탐색, 파라메트릭 서치</title>
      <link>https://zeroone.tistory.com/38</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이진탐색을 사용하기 위한 조건 : &lt;u&gt;정렬되어 있어야 한다.&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾으려는 데이터와 중간점(middle)위치에 있는 데이터를 반복적으로 비교해서 원하는 데이터를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간 복잡도 : O(log(N))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 재귀를 이용한 구현&lt;/p&gt;
&lt;pre id=&quot;code_1646925521145&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

int n, target;
vector&amp;lt;int&amp;gt; v;

int binarySearch(int s, int e, int t) {
    if (s &amp;gt; e)
        return -1;

    int mid = (s + e) / 2;
    if (v[mid] == t) {
        return mid;
    }
    else if (v[mid] &amp;lt; t) {
        return binarySearch(mid+1, e, t);
    }
    else {
        return binarySearch(s, mid-1, t);
    }
}

int main(void) {
    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; target;

    for (int i = 0; i &amp;lt; n; i++) {
        int a;
        cin &amp;gt;&amp;gt; a;
        v.push_back(a);
    }

    cout &amp;lt;&amp;lt; binarySearch(0, n-1, target) + 1 &amp;lt;&amp;lt; &quot;\n&quot;;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) while문을 이용한 구현&lt;/p&gt;
&lt;pre id=&quot;code_1646925545465&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

int n, target;
vector&amp;lt;int&amp;gt; v;

int binarySearch(int t) {
    int s = 0;
    int e = v.size() - 1;

    while (s &amp;lt;= e) {
        int mid = (s + e) / 2;
        if (v[mid] == t) {
            return mid;
        }
        else if (v[mid] &amp;lt; t) {
            s = mid+1;
        }
        else {
            e = mid - 1;
        }
    }

    return - 1;
}
int main(void) {
    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; target;

    for (int i = 0; i &amp;lt; n; i++) {
        int a;
        cin &amp;gt;&amp;gt; a;
        v.push_back(a);
    }

    cout &amp;lt;&amp;lt; binarySearch(target) + 1 &amp;lt;&amp;lt; &quot;\n&quot;;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 경우 2번이 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번, 2번 아무거나 사용하여도 상관 없다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파라메트릭 서치(Parametric Search)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최적화 문제(문제의 상황을 만족하는 특정 변수의 최솟값, 최댓값을 구하는 문제)를 결정 문제(decision problem)로 바꾸어 해결하는 기법&lt;/li&gt;
&lt;li&gt;예를 들어 범위 내에서 조건을 만족하는 가장 큰 값을 찾으라는 최적화 문제라면 이분 탐색으로 결정 문제를 해결하면서 범위를 좁혀갈 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lower Bound, Upper Bound&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이진 탐색으로 돌음&lt;/li&gt;
&lt;li&gt;countByRange 처럼 정렬된 배열에서 a~b까지의 숫자의 개수를 O(logN)으로 찾고자 할때 주로 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lower Bound&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키값보다 크거나 같은 첫번째 값&lt;/li&gt;
&lt;li&gt;찾으려고 하는 key 값이&amp;nbsp;없으면,&amp;nbsp;key 값&amp;nbsp;초과인 값들 중,&amp;nbsp;가장 작은 값&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;Upper Bound &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키값보다 큰 첫번째 값&lt;/li&gt;
&lt;li&gt;최댓값보다 더 큰 값을 찾고자 하는 경우에는,&amp;nbsp;마지막 요소 다음 메모리를 가리키는 iterator(end()와 같은)를 반환한다. 따라서, 이 iterator에 접근하면&amp;nbsp;쓰레기값을 반환.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 구현할 경우는 기존 이진 탐색에서 값을 찾았을 경우 left를 이동할지 right를 이동할지를 생각해 로직을 수정하면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 증명하는 방법은 이진탐색은&amp;nbsp; l~r의 크기가 1 또는 2일 경우를 결국은 지나므로 해당하는 경우를 모두생각해보면 편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 직접 구현&lt;/p&gt;
&lt;pre id=&quot;code_1647442888776&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

int n, key;
vector&amp;lt;int&amp;gt; v;

// Key 보다 크거나 같은 첫번째 값 반환
int lowerBound() {
    int l = 0, r = n-1;

    while (l &amp;lt;= r) {
        int mid = (l + r) / 2;
        if (v[mid] &amp;lt; key) {
            l = mid + 1;
        }
        else {
            r = mid - 1;
        }
    }

    return l;
}

// Key보다 큰 첫번째 값
int upperBound() {
    int l = 0, r = n-1;

    while (l &amp;lt;= r) {
        int mid = (l + r) / 2;
        if ( v[mid] &amp;lt;= key) {
            l = mid + 1;
        }
        else {
            r = mid - 1;
        }
    }

    return l;
}

// 값이 [left, right]인 데이터의 개수를 반환하는 함수
int countByRange() {
    int left = lowerBound();
    int right = upperBound();

    return right - left;
}

int main(void) {
    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; key;
    for (int i = 0; i &amp;lt; n; i++) {
        int x;
        cin &amp;gt;&amp;gt; x;
        v.push_back(x);
    }

    int cnt = countByRange();
    if (cnt == 0) {
        cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;;
    }
    else {
        cout &amp;lt;&amp;lt; cnt &amp;lt;&amp;lt; &quot;\n&quot;;
    }

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) STL&lt;/p&gt;
&lt;pre id=&quot;code_1647442902438&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using namespace std;

int n, key;
vector&amp;lt;int&amp;gt; v;

// 값이 [left, right]인 데이터의 개수를 반환하는 함수
int countByRange() {
    // Key 보다 크거나 같은 첫번째 값 반환
    vector&amp;lt;int&amp;gt;::iterator left = lower_bound(v.begin(), v.end(), key);
    // Key보다 큰 첫번째 값
    vector&amp;lt;int&amp;gt;::iterator right = upper_bound(v.begin(), v.end(), key);

    return right - left;
}

int main(void) {
    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; key;
    for (int i = 0; i &amp;lt; n; i++) {
        int t;
        cin &amp;gt;&amp;gt; t;
        v.push_back(t);
    }

    int cnt = countByRange();
    if (cnt == 0) {
        cout &amp;lt;&amp;lt; -1 &amp;lt;&amp;lt; &quot;\n&quot;; 
    }
    else {
        cout &amp;lt;&amp;lt; cnt &amp;lt;&amp;lt; &quot;\n&quot;;
    }

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/38</guid>
      <comments>https://zeroone.tistory.com/38#entry38comment</comments>
      <pubDate>Fri, 11 Mar 2022 00:20:58 +0900</pubDate>
    </item>
    <item>
      <title>HTTP 메서드 활용</title>
      <link>https://zeroone.tistory.com/37</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;클라이언트에서 서버로 데이터 전송&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2가지 전달방식&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쿼리 파라미터를 통한 데이터 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - GET&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - 주료 정렬 필터(검색어)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지 바디를 통한 데이터 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - POST, PUT, PATCH&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - 처리, 리소스 등록, 리소스 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4가지 상황&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정적 데이터 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 이미지&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;정적 텍스트 문서 &lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적 데이터 조회&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 주로 검색&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;게시판 목록에서 정렬 필터&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;검색어&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- GET - query(쿼리 파라미터, 쿼리 스트링) 사용&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML Form을 통한 데이터 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- HTML 액션을 통합 데이터 전송&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;1) POST 전송&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Content-Type: application/x-www-form-urlencoded &lt;/span&gt;&lt;span&gt;사용 &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;form&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;의 내용을 메시지 바디를 통해서 전송&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(key=value, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;쿼리 파라미터 형식&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;전송 데이터를 url encoding 처리&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;2) GET 전송&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 회원 가입&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;상품 주문&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;데이터 변경&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;3) 파일 업로드&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - Content-Type: multipart/form-data&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - &lt;/span&gt;&lt;span&gt;파일 업로드 같은 바이너리 데이터 전송시 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - &lt;/span&gt;&lt;span&gt;다른 종류의 여러 파일과 폼의 내용 함께 전송 가능&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;그래서 이름이 &lt;/span&gt;&lt;span&gt;multipart) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;참고 : HTML Form 전송은 GET, POST만 지원&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP API를 통한 데이터 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 회원 가입&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;상품 주문&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;데이터 변경&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 서버 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;to &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;서버&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;앱 클라이언트&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;웹 클라이언트&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(Ajax)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span&gt;- Content-Type: application/json&lt;/span&gt;&lt;span&gt;을 주로 사용 &lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;사실상 표준&lt;/span&gt;&lt;span&gt;),&amp;nbsp; &amp;nbsp; TEXT, XML, JSON 등등&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;참고하면 좋은 URI 설계 개념&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;문서&lt;/span&gt;&lt;span&gt;(document) &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;단일 개념&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;파일 하나&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;객체 인스턴스&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;데이터베이스 &lt;/span&gt;&lt;span&gt;row) &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예&lt;/span&gt;&lt;span&gt;) /members/100, /files/star.jpg &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;컬렉션&lt;/span&gt;&lt;span&gt;(collection) &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버가 관리하는 리소스 디렉터리 서버가 리소스의 &lt;/span&gt;&lt;span&gt;URI&lt;/span&gt;&lt;span&gt;를 생성하고 관리 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예&lt;/span&gt;&lt;span&gt;) /members&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;스토어&lt;/span&gt;&lt;span&gt;(store) &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트가 관리하는 자원 저장소 클라이언트가 리소스의 &lt;/span&gt;&lt;span&gt;URI&lt;/span&gt;&lt;span&gt;를 알고 관리 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예&lt;/span&gt;&lt;span&gt;) /files &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;컨트롤러&lt;/span&gt;&lt;span&gt;(controller), &lt;/span&gt;&lt;span&gt;컨트롤 &lt;/span&gt;&lt;span&gt;URI &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문서&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;컬렉션&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;스토어로 해결하기 어려운 추가 프로세스 실행 동사를 직접 사용&lt;br /&gt;예&lt;/span&gt;&lt;span&gt;) /members/{id}/delete &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>HTTP</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/37</guid>
      <comments>https://zeroone.tistory.com/37#entry37comment</comments>
      <pubDate>Sun, 6 Mar 2022 17:37:05 +0900</pubDate>
    </item>
    <item>
      <title>HTTP  메서드</title>
      <link>https://zeroone.tistory.com/36</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;API URI 설계&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 URI 설계란 ? 리소스 식별이 가장 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 리소스와 행위를 분리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리소스 - 명사 - 회원&lt;/li&gt;
&lt;li&gt;행위 - 동사 - 조회, 등록, 삭제, 변경&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URI는 리소스만 식별&lt;/p&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;HTTP &lt;/span&gt;&lt;span&gt;메서드 종류&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;주요 메서드&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GET: 리소스 조회&lt;/li&gt;
&lt;li&gt;POST: 요청 데이터 처리, 주로 등록에 사용&lt;/li&gt;
&lt;li&gt;PUT: 리소스를 대체, 해당 리소스가 없으면 생성&lt;/li&gt;
&lt;li&gt;PATCH: 리소스 부분 변경&lt;/li&gt;
&lt;li&gt;DELETE: 리소스 삭제&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기타 메서드&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HEAD: GET과 동일하지만 메시지 부분을 제외하고, 상태 줄과 헤더만 반환&lt;/li&gt;
&lt;li&gt;OPTIONS: 대상 리소스에 대한 통신 가능 옵션(메서드)을 설명(주로 CORS에서 사용)&lt;/li&gt;
&lt;li&gt;CONNECT: 대상 자원으로 식별되는 서버에 대한 터널을 설정&lt;/li&gt;
&lt;li&gt;TRACE: 대상 리소스에 대한 경로를 따라 메시지 루프백 테스트를 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;주요메서드 분석&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GET&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리소스 조회&lt;/li&gt;
&lt;li&gt;서버에 전달하고 싶은 데이터는 query(쿼리 파라미터, 쿼리 스트링)으로 전달&lt;/li&gt;
&lt;li&gt;메시지 바디를 사용해서 데이터를 전달할 수 있지만&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;지원하지 않는 곳이 많아서 권장하지 않음&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;table style=&quot;border-collapse: collapse; width: 98.1885%; height: 39px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 25px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;request&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 25px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;/members/100&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 41.7282%; height: 25px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;response&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 14px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 14px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;GET /members/100 HTTP/1.1 &lt;br /&gt;Host: localhost:8080 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 14px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;username&quot;: &quot;young&quot;, &lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 20 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 41.7282%; height: 14px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;HTTP/1.1 200 OK &lt;br /&gt;Content-Type: application/json &lt;br /&gt;Content-Length: 34 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp;&quot;username&quot;: &quot;young&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 20 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;post&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청 데이터 처리&lt;/li&gt;
&lt;li&gt;메시지 바디를 통해 서버로 요청 데이터 전달&lt;/li&gt;
&lt;li&gt;서버는 요청 데이터를 처리&lt;/li&gt;
&lt;li&gt;메시지 바디를 통해 들어온 데이터를 처리하는 모든 기능을 수행&lt;/li&gt;
&lt;li&gt;주로 전달된 데이터로 신규 리소스 등록, 프로세스 처리에 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 98.1885%; height: 71px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 25px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;request&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 25px;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;/members -&amp;gt; /&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;members/100 &lt;br /&gt;신규 리소스 식별자 생성&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41.7282%;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;response&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 46px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 46px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;POST /members HTTP/1.1&lt;br /&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;username&quot;: &quot;young&quot;, &lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 20&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 46px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;username&quot;: &quot;young&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 20&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 41.7282%;&quot;&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;HTTP/1.1 201 Created &lt;br /&gt;Content-Type: application/json \&lt;br /&gt;Content-Length: 34&lt;br /&gt;Location: &lt;/span&gt;&lt;span&gt;/members/100 &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;username&quot;: &quot;young&quot;, &lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 20 &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POST처리에 정해진 것이 없다 -&amp;gt; 리소스 URI에 POST 요청이 오면 요청 데이터틑 어떻게 처리할지 리소스마다 따로 정해야 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로, 다음과 같은 경우에 많이 사용한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;새 리소스 생성(등록)&lt;/li&gt;
&lt;li&gt;요청 데이터 처리&lt;/li&gt;
&lt;li&gt;다른 메서드로 처리하기 애매한 경우&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;put&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리소스 대체(있으면 대체 : &lt;u&gt;전체 삭제후 생성&lt;/u&gt; / 없으면 생성)&lt;/li&gt;
&lt;li&gt;클라이언트가 리소스를 식별(URI 지정)&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 98.1885%; height: 35px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 25px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;request&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 25px;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;members/100&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 10px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;(1) 생성&lt;br /&gt;&lt;span&gt;&lt;span&gt;PUT /members/100 HTTP/1.1 &lt;br /&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;username&quot;: &quot;young&quot;, &lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 20&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;div&gt;
&lt;div&gt;(2) 리소스 완전 대체&lt;br /&gt;&lt;span&gt;&lt;span&gt;PUT /members/100 HTTP/1.1&lt;br /&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;// username 없음&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 50&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 10px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;(1) 생성&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;username&quot;: &quot;young&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 20&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(2) 리소스 완전 대체&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;// username 삭제&lt;br /&gt;&amp;nbsp;&amp;nbsp; &quot;age&quot;: 50&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;patch&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;리소스 부분 변경 (put과의 차이)&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 98.1885%; height: 71px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 25px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;request&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 25px;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;members/100&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 46px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 46px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;PATCH /members/100 HTTP/1.1&lt;br /&gt;Content-Type: application/json&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;// username 없음&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 50&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 46px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;username&quot;: &quot;young&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: 20&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;&amp;nbsp;리소스 부분 변경&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;&lt;br /&gt;{&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;username&quot;: &quot;young&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp;&quot;age&quot;: &lt;b&gt;50&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;delete&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 25px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;request&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 25px;&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;/&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;members/100 리소스 제거&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 46px;&quot;&gt;
&lt;td style=&quot;width: 30.3198%; height: 46px;&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;&lt;span&gt;DELETE /members/100 HTTP/1.1 &lt;br /&gt;Host: localhost:8080 &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 27.952%; height: 46px;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;x&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;HTTP 메서드의 속성&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;안전(Safe Methods)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;호출해도 리소스를 변경하지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;멱등(Idempotent Methods)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한번 호출하든 두번 호출하든 결과가 똑같다.&lt;/li&gt;
&lt;li&gt;GET, PUT, DELETE (POST x)&lt;/li&gt;
&lt;li&gt;자동 복구 메커니즘에 활용 가능 : 서버 Time out 등르로 정상 응답을 못주었을 때, 클라이언트가 같은 요청을 다시해도 되는가? 판단 근거, 멱등은 외부 요인으로 중간에 리소스가 변경되는 것까지는 고려하지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;캐시가능(Cacheable Methods)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응답 결과 리소스를 캐시해서 사용해도 되는가?&lt;/li&gt;
&lt;li&gt;GET, HEAD, POST, PATCH 캐시가능&lt;/li&gt;
&lt;li&gt;실제로는 GET, HEAD 정도만 캐시로 사용, POST, PATCH는 본문 내용까지 캐시 키로 고려해야 하는데, 구현이 쉽지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw6jCK/btrvgm6euKK/9QAwZXhoDvmvrzA9GsthDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw6jCK/btrvgm6euKK/9QAwZXhoDvmvrzA9GsthDk/img.png&quot; data-alt=&quot;HTTP웹_기본지식_20201226 출처: https://ko.wikipedia.org/wiki/HTTP&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw6jCK/btrvgm6euKK/9QAwZXhoDvmvrzA9GsthDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw6jCK%2Fbtrvgm6euKK%2F9QAwZXhoDvmvrzA9GsthDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1842&quot; height=&quot;684&quot; data-origin-width=&quot;1842&quot; data-origin-height=&quot;684&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;HTTP웹_기본지식_20201226 출처: https://ko.wikipedia.org/wiki/HTTP&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>HTTP</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/36</guid>
      <comments>https://zeroone.tistory.com/36#entry36comment</comments>
      <pubDate>Sat, 5 Mar 2022 22:52:59 +0900</pubDate>
    </item>
    <item>
      <title>[C++][STL] fill, fill_n</title>
      <link>https://zeroone.tistory.com/35</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559;&quot;&gt;가끔 배열이나 벡터를 전부 초기화 해야할 일이 생긴다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559;&quot;&gt;평소에 for문을 돌려서 초기했다면 fill, fiil_n을 사용해서 코드를 간결하게 만들자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559;&quot;&gt;1) fill&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646132849835&quot; class=&quot;d&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt; class ForwardIt, class T &amp;gt;
void fill( ForwardIt first, ForwardIt last, const T&amp;amp; value );&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559;&quot;&gt;&amp;nbsp;fill(초기 위치, 마지막 위치, 초기화값); (초기위치&amp;lt;= arr &amp;lt; 마지막위치)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;예제 : fill(arr,arr+5,1);&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559;&quot;&gt;2) fill_n&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1646131782711&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;template&amp;lt; class OutputIt, class Size, class T &amp;gt;
void fill_n( OutputIt first, Size count, const T&amp;amp; value );&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;fill_n(초기 위치, 사이즈, 초기화값);&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;예제 : &lt;span style=&quot;background-color: #ffffff; color: #696559;&quot;&gt;fill_n(arr,5,1);&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;0으로 초기화하려면 memset(arr, 0, sizeof(arr)); 이 제일 좋다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;그러나, fill, fill_n을 써도 문제 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;그리고 2차원 이상의 배열의 경우 fill_n은 1차원으로 인식하는 문제가 있으므로 fill을 사용하는 습관을 들이자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;예제 : fill(&amp;amp;arr[0][0], &amp;amp;arr[5][3], 7);&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #696559; font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;결론 : fill 마스터하자&lt;/span&gt;&lt;/p&gt;</description>
      <category>C++ STL</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/35</guid>
      <comments>https://zeroone.tistory.com/35#entry35comment</comments>
      <pubDate>Tue, 1 Mar 2022 20:05:53 +0900</pubDate>
    </item>
    <item>
      <title>HTTP 기본</title>
      <link>https://zeroone.tistory.com/34</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;HTTP : &lt;span&gt;H&lt;/span&gt;&lt;span style=&quot;color: #5e5e5e;&quot;&gt;yper&lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span style=&quot;color: #5e5e5e;&quot;&gt;ext &lt;/span&gt;&lt;span&gt;T&lt;/span&gt;&lt;span style=&quot;color: #5e5e5e;&quot;&gt;ransfer &lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span style=&quot;color: #5e5e5e;&quot;&gt;rotocol&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML, TEXT&lt;/li&gt;
&lt;li&gt;IMAGE, 음성, 영상, 파일&lt;/li&gt;
&lt;li&gt;JSON, XML (API)&lt;/li&gt;
&lt;li&gt;거의 모든 형태의 데이터 전송 가능&lt;/li&gt;
&lt;li&gt;서버간에 데이터를 주고 받을 때도 대부분 HTTP 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;클라이언트 - 서버&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Request - Response 구조&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Stateful, Stateless&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태유지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 항상 같은 서버가 유지되어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;로그인한 사용자의 경우 로그인 했다는 상태를 서버에 유지, 일반적으로 브라우저 쿠키와 서버 세션등을 사용해서 상태 유지&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;- 상태 유지는 최소한만 사용&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 아무 서버나 호출 가능하다. 무한한 서버 증설 가능 (Scale out - 수평확장에 유리)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 서버 개발자가 가장 어려워 하는 부분 - 같은 시간에 딱 맞추어 대규모 트래픽이 발생하는 것을 해결하기 위해 적절히 필요&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Connectionless&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 기본이 비연결성(connectionless)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한계&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TCP/IP 연결을 새로 맺어야 함 - 3 way handshake 시간 추가&lt;/li&gt;
&lt;li&gt;웹 브라우저로 사이트를 요청하면 &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;HTML &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;뿐만 아니라 자바스크립트&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, css, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;추가 이미지 등&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;수 많은 자원이 함께 다운로드&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;극복&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;지금은 HTTP 지속 연결(Persistent Connections)로 문제 해결&lt;/li&gt;
&lt;li&gt;HTTP/2, HTTP/3에서 더 많은 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;HTTP 메시지&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;요청 메시지&amp;gt;&lt;/p&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;start-line = &lt;/span&gt;&lt;u&gt;&lt;span&gt;request-line &lt;/span&gt;&lt;/u&gt;&lt;span&gt;/ status-line&lt;br /&gt;&lt;/span&gt;&lt;span&gt;request-line &lt;/span&gt;&lt;span&gt;= method SP(&lt;/span&gt;&lt;span&gt;공백&lt;/span&gt;&lt;span&gt;) request-target SP HTTP-version CRLF(&lt;/span&gt;&lt;span&gt;엔터&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;method 종류 : GET, POST, PUT, DELETE...&lt;/li&gt;
&lt;li&gt;request target : absolute-path[?query] (절대경로[?쿼리])&amp;nbsp; 참고)&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, http://...?x=y &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;와 같이 다른 유형의 경로지정 방법도 있다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;HTTP-version : ex) HTTP/1.1&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) &lt;span&gt;GET /search?q=hello&amp;amp;hl=ko HTTP/1.1&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Host: &lt;/span&gt;&lt;a style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot; href=&quot;http://www.google.com&quot;&gt;www.google.com&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;응답 메시지&amp;gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;start-line = request-line / &lt;/span&gt;&lt;span&gt;&lt;u&gt;status-line&lt;/u&gt;&lt;br /&gt;status-line &lt;/span&gt;&lt;span&gt;= HTTP-version SP status-code SP reason-phrase CRLF &lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP-version&amp;nbsp;: ex) HTTP/1.1&lt;/li&gt;
&lt;li&gt;status-code : HTTP 상태코드 - 요청 성공, 실패를 나타냄 ex) 200 성공, 400 클라이언트 요청 오류, 500 서버 내부 오류&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ex) &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;Content-Type: text/html;charset=UTF-8 Content-Length: 3423&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;html&amp;gt; &amp;lt;body&amp;gt;...&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;HTTP 헤더 / 메시지 바디&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;HTTP 헤더&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 전송에 필요한 모든 부가정보&lt;/li&gt;
&lt;li&gt;header-field = field-name &quot;:&quot; OWS field-value OWS.&amp;nbsp; &amp;nbsp;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;(OWS : Optional WhiteSpace :&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;띄어쓰기 허용&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;field-name은 대소문자 구문 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ex) 메시지 바디의 내용, 메시지 바디의 크기, 압축, 인증, 캐시 관리 정보 ...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(표준 헤더가 너무 많음, 필요시 임의의 헤더 추가 가능 - hellowordl:hi)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;HTTP 메시지 바디&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 전송할 데이터&lt;/li&gt;
&lt;li&gt;&amp;nbsp;HTML &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;문서&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;이미지&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;영상&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;, JSON &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;등등 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;byte&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;로 표현할 수 있는 모든 데이터 전송 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt; 요청 메시지 예제&amp;gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.1628%; height: 17px;&quot;&gt;요청 메시지&lt;/td&gt;
&lt;td style=&quot;width: 36.0465%; height: 17px;&quot;&gt;GET /search?q=hello&amp;amp;hl=ko HTTP/1.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 35px;&quot;&gt;
&lt;td style=&quot;width: 16.1628%; height: 35px;&quot;&gt;HTTP 헤더&lt;/td&gt;
&lt;td style=&quot;width: 36.0465%; height: 35px;&quot;&gt;&lt;span&gt;Host:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;http://www.google.com/&quot;&gt;www.google.com&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt; 응답 메시지 예제&amp;gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 52.2093%; height: 87px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 16.1628%; height: 17px;&quot;&gt;응답 메시지&lt;/td&gt;
&lt;td style=&quot;width: 36.0465%; height: 17px;&quot;&gt;&lt;span&gt;HTTP/1.1 200 OK&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 35px;&quot;&gt;
&lt;td style=&quot;width: 16.1628%; height: 35px;&quot;&gt;HTTP 헤더&lt;/td&gt;
&lt;td style=&quot;width: 36.0465%; height: 35px;&quot;&gt;Content-Type: text/html;charset=UTF-8&lt;br /&gt;Content-Length: 3423&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 35px;&quot;&gt;
&lt;td style=&quot;width: 16.1628%; height: 35px;&quot;&gt;HTTP 메시지 바디&lt;/td&gt;
&lt;td style=&quot;width: 36.0465%; height: 35px;&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;lt;html&amp;gt; &amp;lt;body&amp;gt;...&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 단순핟고 확장가능한 기술이다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>HTTP</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/34</guid>
      <comments>https://zeroone.tistory.com/34#entry34comment</comments>
      <pubDate>Tue, 1 Mar 2022 18:23:49 +0900</pubDate>
    </item>
    <item>
      <title>URI와 웹 브라우저 요청 흐름</title>
      <link>https://zeroone.tistory.com/33</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;URI(Uniform Resource Identifier) :&amp;nbsp; 자원을 식별하는 통일된 방식&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;URL(Resource Locator)&lt;/li&gt;
&lt;li&gt;URN(Resource Name)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URN 이름만으로 실제 리소스를 찾을 수 있는 방법이 보편화&amp;nbsp; 되지 않아 URL을 보통 URI로 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; foo://example.com:8042/over/there?name=ferret#nose&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; - URL&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;\_/&amp;nbsp; &amp;nbsp; \________________/\_________/ \_________/&amp;nbsp; &amp;nbsp;\__/&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;|&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; |&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;|&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;|&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;|&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;scheme&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;authority&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; path&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;query&amp;nbsp;&amp;nbsp;&amp;nbsp;fragment&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; |&amp;nbsp;&amp;nbsp;&amp;nbsp;_____________________|__&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;/\&amp;nbsp; &amp;nbsp;/&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; \&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; urn:example:animal:ferret:nose&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- URN&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;URL&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;scheme://[userinfo@]host[:port][/path][?query][#fragment]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;a style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot; href=&quot;https://www.google.com:443/search?q=hello&amp;amp;hl=ko&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt; ex ) https://www.google.com:443/search?q=hello&amp;amp;hl=ko&lt;/a&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;nbsp; 프로토콜(https)&lt;/li&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;nbsp; 호스트명(www.google.com) - 도메인명 또는 IP주소&lt;/li&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;nbsp; 사용자정보 - 거의 사용하지 않음&lt;/li&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;nbsp; 포트 번호(443) - 일반적으로 생략, 디폴트로 http 80, https 443&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;nbsp; 패스(/search) - 경로, 계층적 구조&lt;/li&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;nbsp; 쿼리 파라미터(q=hello&amp;amp;hl=ko) - key=value 형태, ?로 시작, &amp;amp;로 추가, 웹서버에 제공하는 파라미터, 문자형태,&lt;/li&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; query string으로도 불림&lt;/li&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;nbsp; fragment - html 내부 북마크 등에 사용, 서버에 전송 안함. (-&amp;gt;자세히는 나중에)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;웹 브라우저 요청 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;984&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGr2Sz/btrufD8Tggx/Vtewq2OOQu8gllMCUyGkjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGr2Sz/btrufD8Tggx/Vtewq2OOQu8gllMCUyGkjk/img.png&quot; data-alt=&quot;1) URL을 분석해 HTTP 메시지를 만든다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGr2Sz/btrufD8Tggx/Vtewq2OOQu8gllMCUyGkjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGr2Sz%2FbtrufD8Tggx%2FVtewq2OOQu8gllMCUyGkjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;633&quot; height=&quot;259&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;984&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;1) URL을 분석해 HTTP 메시지를 만든다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2640&quot; data-origin-height=&quot;1182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baYd9G/btruaiLuAJi/nIheezo9X8jAozIiE8tg5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baYd9G/btruaiLuAJi/nIheezo9X8jAozIiE8tg5k/img.png&quot; data-alt=&quot;2) 인터넷 네트워크 편에서 설명한 것처럼 HTTP 메시지에 TCP/IP 패킷이 붙고 Ethernet Frame도 씌워진다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baYd9G/btruaiLuAJi/nIheezo9X8jAozIiE8tg5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaYd9G%2FbtruaiLuAJi%2FnIheezo9X8jAozIiE8tg5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;601&quot; height=&quot;269&quot; data-origin-width=&quot;2640&quot; data-origin-height=&quot;1182&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2) 인터넷 네트워크 편에서 설명한 것처럼 HTTP 메시지에 TCP/IP 패킷이 붙고 Ethernet Frame도 씌워진다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2432&quot; data-origin-height=&quot;1196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JMg4C/btrt7ulOSwO/jDlHMfK4QyVzKicHtM0Il0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JMg4C/btrt7ulOSwO/jDlHMfK4QyVzKicHtM0Il0/img.png&quot; data-alt=&quot;3)  요청 패킷 전달&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JMg4C/btrt7ulOSwO/jDlHMfK4QyVzKicHtM0Il0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJMg4C%2Fbtrt7ulOSwO%2FjDlHMfK4QyVzKicHtM0Il0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;683&quot; height=&quot;336&quot; data-origin-width=&quot;2432&quot; data-origin-height=&quot;1196&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;3)  요청 패킷 전달&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.23.30.png&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/022Nd/btrt7ue7vCb/cApDtWDxfLyLHOr4SVAD5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/022Nd/btrt7ue7vCb/cApDtWDxfLyLHOr4SVAD5k/img.png&quot; data-alt=&quot;4) 요청 패킷 도착&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/022Nd/btrt7ue7vCb/cApDtWDxfLyLHOr4SVAD5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F022Nd%2Fbtrt7ue7vCb%2FcApDtWDxfLyLHOr4SVAD5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;694&quot; height=&quot;346&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.23.30.png&quot; data-origin-width=&quot;2420&quot; data-origin-height=&quot;1206&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;4) 요청 패킷 도착&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.24.24.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;704&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnvPju/btrt82WTRVq/TZwFKE9BzPiMS5wEC3vIXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnvPju/btrt82WTRVq/TZwFKE9BzPiMS5wEC3vIXK/img.png&quot; data-alt=&quot;5) 응답 메시지도 요청 메시지와 동일하게 HTTP 메시지에 TCP/IP 패킷이 붙고 Ethernet Frame도 씌워져 전달된다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnvPju/btrt82WTRVq/TZwFKE9BzPiMS5wEC3vIXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnvPju%2Fbtrt82WTRVq%2FTZwFKE9BzPiMS5wEC3vIXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;636&quot; height=&quot;286&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.24.24.png&quot; data-origin-width=&quot;1564&quot; data-origin-height=&quot;704&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;5) 응답 메시지도 요청 메시지와 동일하게 HTTP 메시지에 TCP/IP 패킷이 붙고 Ethernet Frame도 씌워져 전달된다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.24.46.png&quot; data-origin-width=&quot;2408&quot; data-origin-height=&quot;1204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q2iPC/btrub89INSE/A9MxJiUECmf1UqcJWCK5L1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q2iPC/btrub89INSE/A9MxJiUECmf1UqcJWCK5L1/img.png&quot; data-alt=&quot;6) 응답 패킷 전달&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q2iPC/btrub89INSE/A9MxJiUECmf1UqcJWCK5L1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq2iPC%2Fbtrub89INSE%2FA9MxJiUECmf1UqcJWCK5L1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;722&quot; height=&quot;361&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.24.46.png&quot; data-origin-width=&quot;2408&quot; data-origin-height=&quot;1204&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;6) 응답 패킷 전달&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.24.56.png&quot; data-origin-width=&quot;2414&quot; data-origin-height=&quot;1206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4i11u/btrt9U5me8k/oaN07Tp6Xbr6Fy1aJYSBkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4i11u/btrt9U5me8k/oaN07Tp6Xbr6Fy1aJYSBkk/img.png&quot; data-alt=&quot;7) 응답 패킷 도착&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4i11u/btrt9U5me8k/oaN07Tp6Xbr6Fy1aJYSBkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4i11u%2Fbtrt9U5me8k%2FoaN07Tp6Xbr6Fy1aJYSBkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;734&quot; height=&quot;367&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.24.56.png&quot; data-origin-width=&quot;2414&quot; data-origin-height=&quot;1206&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;7) 응답 패킷 도착&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.25.08.png&quot; data-origin-width=&quot;2408&quot; data-origin-height=&quot;1210&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1fRHE/btrubtzn6gg/f3TWjtDUpyKAH99EuSkY11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1fRHE/btrubtzn6gg/f3TWjtDUpyKAH99EuSkY11/img.png&quot; data-alt=&quot;8) 응답 받은 메시지 렌더링&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1fRHE/btrubtzn6gg/f3TWjtDUpyKAH99EuSkY11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1fRHE%2Fbtrubtzn6gg%2Ff3TWjtDUpyKAH99EuSkY11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;742&quot; height=&quot;373&quot; data-filename=&quot;스크린샷 2022-02-24 오전 12.25.08.png&quot; data-origin-width=&quot;2408&quot; data-origin-height=&quot;1210&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;8) 응답 받은 메시지 렌더링&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>HTTP</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/33</guid>
      <comments>https://zeroone.tistory.com/33#entry33comment</comments>
      <pubDate>Thu, 24 Feb 2022 00:33:07 +0900</pubDate>
    </item>
    <item>
      <title>인터넷 네트워크</title>
      <link>https://zeroone.tistory.com/32</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인터넷 프로토콜 스택의 4계층 (TCP/IP 4계층)&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 36.9767%; height: 189px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 7.69071%; height: 25px;&quot;&gt;계층&lt;/td&gt;
&lt;td style=&quot;width: 17.3093%; height: 25px;&quot;&gt;프로토콜 종류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 7.69071%; height: 25px;&quot;&gt;애플리케이션&lt;/td&gt;
&lt;td style=&quot;width: 17.3093%; height: 25px;&quot;&gt;HTTP, FTP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 7.69071%; height: 25px;&quot;&gt;전송&lt;/td&gt;
&lt;td style=&quot;width: 17.3093%; height: 25px;&quot;&gt;TCP, UDP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 7.69071%; height: 25px;&quot;&gt;인터넷&lt;/td&gt;
&lt;td style=&quot;width: 17.3093%; height: 25px;&quot;&gt;IP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 7.69071%; height: 25px;&quot;&gt;네트워크 &lt;br /&gt;인터페이스&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 17.3093%; height: 25px;&quot;&gt;LAN 드라이버, LAN 장비&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;송신시 동작 순서&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;872&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chFMvK/btrtieDzGCk/V3A9bYjFcv8c989q5jz14k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chFMvK/btrtieDzGCk/V3A9bYjFcv8c989q5jz14k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chFMvK/btrtieDzGCk/V3A9bYjFcv8c989q5jz14k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchFMvK%2FbtrtieDzGCk%2FV3A9bYjFcv8c989q5jz14k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;715&quot; height=&quot;872&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;872&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;각 Layer에서 저장되는 정보&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-02-14 오후 11.44.43.png&quot; data-origin-width=&quot;2206&quot; data-origin-height=&quot;1356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ijze0/btrteiT1n5o/NvjWPksJmPa6mJafE4gIJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ijze0/btrteiT1n5o/NvjWPksJmPa6mJafE4gIJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ijze0/btrteiT1n5o/NvjWPksJmPa6mJafE4gIJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIjze0%2FbtrteiT1n5o%2FNvjWPksJmPa6mJafE4gIJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;543&quot; height=&quot;1356&quot; data-filename=&quot;스크린샷 2022-02-14 오후 11.44.43.png&quot; data-origin-width=&quot;2206&quot; data-origin-height=&quot;1356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3-way-handshake&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 데이터 전송전 연결을 확인한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;접속요청 : SYN&amp;nbsp; &amp;nbsp;-&amp;gt;&lt;/li&gt;
&lt;li&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;- ACK+SYN : 요청 수락 + 접속요청&lt;/li&gt;
&lt;li&gt;요청수락 : ACK&amp;nbsp; &amp;nbsp;-&amp;gt;&lt;/li&gt;
&lt;li&gt;데이터 전송 (&lt;i&gt;참고 : 3.ACK와 함께 데이터 전송 가능&lt;/i&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;TCP와 UDP 차이&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 136px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;TCP&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;UDP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;연결지향&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;연결지향 - 3 way handshake (가상 연결)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;x, 기능이 거의 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;데이터 전달 보증&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;데이터 전달 보증&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;순서 보장 (packet 1, 2, 3 -&amp;gt; 1, 2, 3)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;순서 보장&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;신뢰성&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;신뢰할 수 있다&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;속도&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;느림&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;빠름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;결론&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;현재는 대부분 TCP 사용&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px;&quot;&gt;IP와 거의 같다. + port + 체크섬 정도만 추가&lt;br /&gt;애플리케이션에서 추가작업 필요.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;PORT&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 IP 내 프로세스 구분 ( 서버에 두개의 애플리케이션이 띄워져 있고 두개의 애플리케이션에 접근하고자 한다면 Port를 이용해 구분하여 붙을 수 있다 )&lt;/li&gt;
&lt;li&gt;&amp;nbsp;따라서 TCP 세그먼트에 출발지, 목적지 PORT 추가.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2040&quot; data-origin-height=&quot;1058&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3mSJk/btrtjQiaNiW/xMOk2qULDX2V5gkIQisjSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3mSJk/btrtjQiaNiW/xMOk2qULDX2V5gkIQisjSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3mSJk/btrtjQiaNiW/xMOk2qULDX2V5gkIQisjSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3mSJk%2FbtrtjQiaNiW%2FxMOk2qULDX2V5gkIQisjSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;683&quot; height=&quot;354&quot; data-origin-width=&quot;2040&quot; data-origin-height=&quot;1058&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DNS&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Domain Name System&lt;/li&gt;
&lt;li&gt;IP 기억하기 어려우니 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-02-15 오전 12.26.39.png&quot; data-origin-width=&quot;2354&quot; data-origin-height=&quot;1252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ybOav/btrs8RbedLU/raUKonFxbThaoY8D34vak0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ybOav/btrs8RbedLU/raUKonFxbThaoY8D34vak0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ybOav/btrs8RbedLU/raUKonFxbThaoY8D34vak0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FybOav%2Fbtrs8RbedLU%2FraUKonFxbThaoY8D34vak0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2354&quot; height=&quot;1252&quot; data-filename=&quot;스크린샷 2022-02-15 오전 12.26.39.png&quot; data-origin-width=&quot;2354&quot; data-origin-height=&quot;1252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;참고&amp;gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;해당 포스팅은 인프런의 김영한님이 강의하신&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href=&quot;https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC&quot;&gt;HTTP 강의&lt;/a&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 수강하고, 이해를 정리한 기록들이며 모든 자료의 출처는 강의의 강의자료이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>HTTP</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/32</guid>
      <comments>https://zeroone.tistory.com/32#entry32comment</comments>
      <pubDate>Tue, 15 Feb 2022 00:28:25 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][오답노트] [이코테] 4. 만들 수 없는 금액</title>
      <link>https://zeroone.tistory.com/31</link>
      <description>&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;편의점 주인인 동빈이는 N개의 동전을 가지고 있다.&lt;br /&gt;N개의 동전을 이용하여 만들 수 없는 양의 정수 금액 중 최솟값을 구하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N = 5이고, 각 동전이 각각 3원, 2원, 1원, 1원, 9원짜리 동전이라고 가정하자. 이때 동빈이가 만들 수 없는 양의 정수 금액 중 최솟값은 8원이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N = 3이고 각 동전이 각각 3원, 5원, 7원이면, 만들 수 없는 양의 정수 금액 중 최솟값은 1원이다.&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id=&quot;입력-조건&quot; data-ke-size=&quot;size26&quot;&gt;입력&amp;nbsp;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫째 줄에는 동전의 개수를 나타내는 양의 정수 N이 주어진다. ( 1 &amp;lt;= N 1,000)&lt;/li&gt;
&lt;li&gt;둘째 줄에는 각 동전의 화폐 단위를 나타내는 N개의 자연수가 주어지며 각 자연수는 공백으로 구분된다. 각 화폐 단위는 1,000,000 이하의 자연수이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;출력-조건&quot; data-ke-size=&quot;size26&quot;&gt;출력&amp;nbsp;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;첫째 줄에 주어진 동전들로 만들 수 없는 양의 정수 금액 중 최솟값을 출력한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;입력-예시&quot; data-ke-size=&quot;size26&quot;&gt;입력 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100.698%; height: 71px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px; width: 47.6905%;&quot;&gt;5&amp;nbsp;&lt;br /&gt;3&amp;nbsp;2&amp;nbsp;1&amp;nbsp;1&amp;nbsp;9&lt;/td&gt;
&lt;td style=&quot;height: 17px; width: 52.194%;&quot;&gt;8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&quot;입력-예시&quot; data-ke-size=&quot;size26&quot;&gt;느낀점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 처음 보면 그리디 알고리즘이라고 생각하기 힘든 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 알고나면 너무 쉬운 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 유형이라고 생각하고 외워두면 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 풀어내는 사고방식은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 동전부터 탐색하면서, 만들고자 하는 금액(target)을 아직 이용하지 않고 가장 작은 금액의 동전이 만들고자 하는 금액 이하이면 해당 금액을 그 전에 이용한 동전과 조합해 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 전에 이용했던 동전들로 1~target-1의 금액을 만들 수 있고 이용하지 않은 가장 작은 금액의 동전이 target 보다 작다면&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;이용하지 않은 가장 작은 금액의 동전 ( &amp;lt;= target) + (1~target-1) &lt;span style=&quot;background-color: #ffffff; color: #202124;&quot;&gt;&amp;ni;&lt;/span&gt;&amp;nbsp;target&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 성립한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 동전들을 정렬한 후, 하나씩 뽑으면서 다음 target을  업데이트해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644648757724&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

int n;

vector&amp;lt;int&amp;gt; v;
int main(void) {
    cin &amp;gt;&amp;gt; n;
    for (int i = 0; i &amp;lt; n; i++) {
        int x;
        cin &amp;gt;&amp;gt; x;
        v.push_back(x);
    }

    // 1. 정렬
    sort(v.begin(), v.end());

    // 2. 첫번째 target은 1, 이용하기 전의 가장 작은 동전이 target이하여야 target을 만들 수 있다.
    int target = 1;
    for (int i = 0; i &amp;lt; n; i++) {
        if (v[i] &amp;lt;= target) {
            target += v[i];
        }
        else {
            // 만들 수 없는 금액 종료
            break;
        }
    }

    cout &amp;lt;&amp;lt; target &amp;lt;&amp;lt; &quot;\n&quot;;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/오답노트</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/31</guid>
      <comments>https://zeroone.tistory.com/31#entry31comment</comments>
      <pubDate>Sat, 12 Feb 2022 15:56:32 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm] 정렬</title>
      <link>https://zeroone.tistory.com/30</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;정렬에는 여러가지 방식이 있고 다음 4가지 정렬만 우선 다루려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설명은 오름차순 기준으로 진행하므로 내림차순은 반대로 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 선택정렬(Selection Sort)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - O(N^2)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - k번째 작은 데이터를 가져와 k번째 위치에 놓는다.&lt;/p&gt;
&lt;pre id=&quot;code_1644243965867&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

vector&amp;lt;int&amp;gt; arr {7, 5, 9, 0, 3, 1, 6, 2, 4, 8};

int main(void) {

    // 삽입정렬
    for (int i = 0; i &amp;lt; arr.size(); i++) {
        for (int j = i; j &amp;gt; 0; j--) {
            if (arr[j] &amp;lt; arr[j-1]) {
                swap(arr[j], arr[j-1]);
            }
        }
    }

    for (int i = 0; i &amp;lt; arr.size(); i++) {
        cout &amp;lt;&amp;lt; arr[i] &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 삽입정렬(Insertion Sort)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - O(N^2)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 데이터를 하나씩 확인하며, 각 데이터를 적절한 위치에 삽입한다.&lt;/p&gt;
&lt;pre id=&quot;code_1644243957129&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

vector&amp;lt;int&amp;gt; arr {7, 5, 9, 0, 3, 1, 6, 2, 4, 8};

int main(void) {

    // 선택정렬
    for (int i = 0; i &amp;lt; arr.size(); i++) {
        int min_index = i;
        for (int j = i+1; j &amp;lt; arr.size(); j++) {
            if (arr[min_index] &amp;gt; arr[j]) {
                min_index = j;
            }
        }
        swap(arr[min_index], arr[i]);
    }

    for (int i = 0; i &amp;lt; arr.size(); i++) {
        cout &amp;lt;&amp;lt; arr[i] &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 퀵정렬(Quick Sort)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - O(N^2)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 호어 분할 방식 : 리스트에서 첫번째 데이터를 pivot으로 정한다. 이외에도 많은 pivot의 기준을 잡는 방식은 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 1) pivot을 기준으로 왼쪽에서부터 pivot보다 큰 데이터를 찾고&amp;nbsp; 오른쪽부터 pivot보다 작은 데이터를 찾아 교환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 2) 1) 을 반복하다 작은 데이터와 큰 데이터가 바뀌면 작은 데이터와 pivot을 바꾼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 3) pivot으로 분할된 왼쪽 리스트와 오른쪽 리스트에 대해 각각 1), 2)를 반복수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;*C++ sort의 경우 퀵 정렬을 기반으로 하지만 피벗값을 설정할 때 추가적인 로직을 더해 O(NlogN)을 보장한다.&lt;/p&gt;
&lt;pre id=&quot;code_1644243946056&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

vector&amp;lt;int&amp;gt; arr {7, 5, 9, 0, 3, 1, 6, 2, 4, 8};

void quickSort(int start, int end) {
    // 원소가 한개인 경우 종료
    if (start &amp;gt;= end) {
        return;
    }

    // 호어 분할 방식 : pivot은 첫번째 원소
    int pivot = start;
    int left = pivot+1;
    int right = end;

    while (left &amp;lt;= right) {
        // pivot보다 큰 데이터를 찾을 때까지 반복 (배열을 초과하지 않을 정도로만)
        while (left &amp;lt;= end &amp;amp;&amp;amp; arr[left] &amp;lt;= arr[pivot]) {
            left++;
        }
        // pivot보다 작은 데이터를 찾을 때까지 반복 (pivot index보다 커야함)
        while (right &amp;gt; start &amp;amp;&amp;amp; arr[right] &amp;gt;= arr[pivot]) {
            right--;
        }
        // 엇갈렸다면 작은 데이터와 pivot을 교체
        if (left &amp;gt; right) {
            swap(arr[right], arr[pivot]);
        }
        // 엇갈리지 않았다면 큰 데이터와 작은 데이터를 교체
        else {
            swap(arr[left], arr[right]);
        }
    }

    // 분할 후, 왼쪽 리스트와 오른쪽 리스트에서 각각 반복수행
    quickSort(start, right-1);
    quickSort(right+1, end);

}

int main(void) {

    quickSort(0, arr.size()-1);

    for (int i = 0; i &amp;lt; arr.size(); i++) {
        cout &amp;lt;&amp;lt; arr[i] &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; &quot;\n&quot;;
    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계수 정렬(Counting Sort)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;O(N+K)&lt;/li&gt;
&lt;li&gt;정렬된 리스트에 가장 작은 데이터부터 큰 데이터까지의 빈도를 세서 저장해주는 것이다. 말 그대로 count다.&lt;/li&gt;
&lt;li&gt;가장 큰 데이터와 가장 작은 데이터의 차이가 1,000,000을 넘지 않을 때 효과적이다. (이를 넘어가면 공간 복잡도를 초과한다.)&lt;/li&gt;
&lt;li&gt;즉, 시간 복잡도를 위해 공간 복잡도를 희생한다.&lt;/li&gt;
&lt;li&gt;말도 안되게 빠른 정렬을 요하는 문제는 무조건 계수정렬이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1644244471727&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

#define MAX_VALUE 9

using namespace std;

int n = 15;
// 모든 원소의 값이 0보다 크거나 같다고 가정
int arr[15] = {7, 5, 9, 0, 3, 1, 6, 2, 9, 1, 4, 8, 0, 5, 2};
// 모든 범위를 포함하는 배열 선언(모든 값은 0으로 초기화)
int cnt[MAX_VALUE + 1];

int main(void) {
    for (int i = 0; i &amp;lt; n; i++) {
        cnt[arr[i]] += 1; // 각 데이터에 해당하는 인덱스의 값 증가
    }
    for (int i = 0; i &amp;lt;= MAX_VALUE; i++) { // 배열에 기록된 정렬 정보 확인
        for (int j = 0; j &amp;lt; cnt[i]; j++) {
            cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; ' '; // 띄어쓰기를 기준으로 등장한 횟수만큼 인덱스 출력
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/30</guid>
      <comments>https://zeroone.tistory.com/30#entry30comment</comments>
      <pubDate>Mon, 7 Feb 2022 23:35:31 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template]  DFS와 BFS</title>
      <link>https://zeroone.tistory.com/29</link>
      <description>&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;DFS&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;BFS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;동작원리&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;스택&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;큐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;구현방법&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;*재귀함수 이용&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;큐 자료구조 이용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;시간복잡도&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;O(N)&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;O(N)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*재귀함수 : 자기 자신을 다시 호출하는 함수, 종료조건을 반드시 명시해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS 동작과정&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;탐색 시작 노드를 스택에 삽입하고 방문 처리를 한다.&lt;/li&gt;
&lt;li&gt;스택의 최상단 노드에 방문하지 않은 인접 노드가 있으면 그 인접 노드를 스택에 넣고 방문 처리를 한다. 방문하지 않은 인접 노드가 없으면 스택에서 최상단 노드를 꺼낸다. (방문처리 순서가 중요하다. 스택에 삽입되면서 준비상태가 되면 방문처리가 되어야 한다.)&lt;/li&gt;
&lt;li&gt;2번 과정을 더 이상 수행할 수 없을 때까지 반복한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 재귀함수 자체가 스택형식으로 작동한다. (함수호출 - 스택에 삽입, 함수 종료 - 스택에서 제거)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 즉, DFS는 재귀함수를 이용하면 스택을 따로 선언하여 사용할 필요가 없다. 따라서 BFS보다 구현이 간편하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644054035890&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; graph = {
    vector&amp;lt;int&amp;gt; {},
    vector&amp;lt;int&amp;gt; {2, 3, 8},
    vector&amp;lt;int&amp;gt; {1, 7},
    vector&amp;lt;int&amp;gt; {1, 4, 5},
    vector&amp;lt;int&amp;gt; {3, 5},
    vector&amp;lt;int&amp;gt; {3, 4},
    vector&amp;lt;int&amp;gt; {7},
    vector&amp;lt;int&amp;gt; {2, 6, 8},
    vector&amp;lt;int&amp;gt; {1, 7}
};
bool visited[101];

// DFS 함수 정의
// 탐색 시작 노드 스택 삽입
void dfs(int now) {
    // 현재 노드를 방문 처리
    visited[now] = true;
    cout &amp;lt;&amp;lt; now &amp;lt;&amp;lt; &quot; &quot;;
    // 현재 노드의 인접 노드 중 방문하지 않은 노드 재귀적으로 방문
    for (int next : graph[now]) {
        if (!visited[next]) {
            dfs(next);
        }
    }
// 현재(최상단) 노드 스택에서 꺼내기
}
int main(void) {

    dfs(1);
    cout &amp;lt;&amp;lt; &quot;\n&quot;;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS 동작과정&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;탐색 시작 노드를 큐에 삽입하고 방문 처리를 한다.&lt;/li&gt;
&lt;li&gt;큐에서 노드를 꺼내 해당 노드의 인접 노드 중에서 방문하지 않은 노드를 전부 큐에 삽입하고 방문처리를 한다. (방문처리 순서가 중요하다. 큐에 삽입되면서 준비상태가 되면 방문처리가 되어야 한다.)&lt;/li&gt;
&lt;li&gt;2번 과정을 더 이상 수행할 수 없을 때까지 반복한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 일반적인 경우 BFS가 DFS보다 성능이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1644054105894&quot; class=&quot;c++ arduino&quot; data-ke-language=&quot;c++&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;queue&amp;gt;

using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; graph = {
    vector&amp;lt;int&amp;gt; {},
    vector&amp;lt;int&amp;gt; {2, 3, 8},
    vector&amp;lt;int&amp;gt; {1, 7},
    vector&amp;lt;int&amp;gt; {1, 4, 5},
    vector&amp;lt;int&amp;gt; {3, 5},
    vector&amp;lt;int&amp;gt; {3, 4},
    vector&amp;lt;int&amp;gt; {7},
    vector&amp;lt;int&amp;gt; {2, 6, 8},
    vector&amp;lt;int&amp;gt; {1, 7}
};
bool visited[101];

// BFS 함수 정
void bfs(int start) {
    queue&amp;lt;int&amp;gt; q;

    // 탐색 시작 노드 큐에 삽입
    q.push(start);
    // 현재 노드를 방문 처리
    visited[start] = true;
    
    // 큐가 빌때까지 반복
    while(!q.empty()) {
        // 큐에서 원소 하나 뽑기
        int now = q.front();
        cout &amp;lt;&amp;lt; now &amp;lt;&amp;lt; &quot; &quot;;
        q.pop();

        // 해당 원소와 연결된, 아직 방문하지 않은 노 큐에 삽입 후 방문처리
        for (int next : graph[now]){
            if (!visited[next]) {
                q.push(next);
                visited[next] = true;
            }
        }
    }
}
int main(void) {

    bfs(1);
    cout &amp;lt;&amp;lt; &quot;\n&quot;;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 트리의 깊이를 묻는 문제는 BFS를 사용하자. 둘 다 사용할 수 있어도 BFS를 쓰자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/29</guid>
      <comments>https://zeroone.tistory.com/29#entry29comment</comments>
      <pubDate>Sat, 5 Feb 2022 18:42:19 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm] 그리디 알고리즘</title>
      <link>https://zeroone.tistory.com/28</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;그리디 알고리즘(Greedy algorithm) : 탐욕법, 현재 상황에서 지금 당장 좋은 것만 고르는 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리디 알고리즘의 대표적인 예제는 거스름돈이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마트에 가서 현금으로 결제하면 직원은 우리에게 '가장 큰 화폐단위'부터 돈을 거슬러 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것이 가장 적은 화폐수로 거스름돈을 줄 수 있는 방법이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정당성을 어떻게 보장하는가?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리디 알고리즘의 정당성 : 그리디 알고리즘을 이용해도 '최적의 해'를 찾을 수 없는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거스름돈의 예에서, 어떤 화폐는 그것보다 작은 단위의 배수이므로 작은 단위의 동전들을 종합해 다른 해가 나올 수 없나는 사실이 정당성을 증명한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리나라 화폐는 10, 50, 100, 500, 1000, 5000, 10000, 50000이다. 즉 배수로 증가함을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에, 600원짜리 화폐가 등장한다면 그리디 알고리즘의 정당성을 충족하지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 그리디 알고리즘의 문제에서는 문제풀이 아이디어를 그리디로 접근했다면 이것이 정당한지를 검토할 수 있어야 한다.&lt;/p&gt;</description>
      <category>알고리즘</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/28</guid>
      <comments>https://zeroone.tistory.com/28#entry28comment</comments>
      <pubDate>Sat, 5 Feb 2022 17:53:06 +0900</pubDate>
    </item>
    <item>
      <title>객체지향 프로그래밍이란?</title>
      <link>https://zeroone.tistory.com/27</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 프로그래밍이란?&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 지향 프로그래밍은 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나 여러 개의 독립된 단위, 즉 &quot;객체&quot;들의 모임으로 파악하고자 하는 것이다. 각각의 객체는 메시지 를 주고받고, 데이터를 처리할 수 있다. (협력)&lt;/li&gt;
&lt;li&gt;객체 지향 프로그래밍은 프로그램을 유연하고 변경이 용이하게 만들기 때문에 대규모 소프트웨어 개발에 많이 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향의 특징 4가지&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추상화&lt;/li&gt;
&lt;li&gt;캡슐화&lt;/li&gt;
&lt;li&gt;상속&lt;/li&gt;
&lt;li&gt;다형성&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역할과 구현으로 분리(다형성)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 언어의 다형성을 활용&lt;/li&gt;
&lt;li&gt;&amp;nbsp;역할 = 인터페이스&lt;/li&gt;
&lt;li&gt;&amp;nbsp;구현 =&amp;nbsp; 클래스, 객체&lt;/li&gt;
&lt;li&gt;단순해져 변경에 유연해진다.&lt;/li&gt;
&lt;li&gt;클라이언트를 변경하지 않고, 서버의 유현기능만을 유연하게 변경 가능하다.&lt;/li&gt;
&lt;li&gt;확장에 유연&lt;/li&gt;
&lt;li&gt;인터페이스를 안정적으로 잘 설계하는 것이 중요하다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향에선 다형성이 가장 중요한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 다형성을 극대화하여 사용할 수 있게 도와준다. ex) IoC, DI&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;SOLID&lt;br /&gt;&lt;/span&gt;&lt;span&gt;클린코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;가지 원칙을 정리&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SRP: 단일 책임 원칙(single responsibility principle)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 한 클래스는 하나의 책임만 가져야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 변경이 있을 때 파급효과가 적어야 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OCP: 개방-폐쇄 원칙 (Open/closed principle)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 다음과 같이 다형성을 활용해 역할과 구현을 분리해도 서버단의 구현객체를 변경하려면 클라이언트 코드를 변경해야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1643627955735&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MemberRepository m = new MemoryMemberRepository(); //기존 코드
MemberRepository m = new JdbcMemberRepository(); //변경 코드&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 객체를 생성하고&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;연관관계를 맺어주는 별도의 조립&lt;/span&gt;&lt;span&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;설정자가 필요하다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;LSP: 리스코프 치환 원칙 (Liskov substitution principle)
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; - 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.&lt;br /&gt;&amp;nbsp; - &lt;/span&gt;부모 클래스의 행동규약을 자식 클래스가 위반하지 말아야 한다.&lt;br /&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 오버라이딩 잘 못 하는 경우&lt;b&gt; :&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;  1. 자식 클래스가 부모 클래스의 변수의 타입을 바꾸거나 메소드의 파라미터 또는 리턴값의 타입 or 갯수를 바꾸는 경우
  2. 자식 클래스가 부모 클래스의 의도와 다르게 메소드를 오버라이딩 하는 경우&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;ISP: 인터페이스 분리 원칙 (Interface segregation principle)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;즉, 역할을 여러 개로 구별하여 쪼개자.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DIP: 의존관계 역전 원칙 (Dependency inversion principle)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 추상화에 의존해야지 구체화에 의존하면 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 즉, 인터페이스에 의존하게 만들자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- 위의 OCP 예제 코드도 구현에 의존되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론 : 다형성만으로는 OCP, DIP를 지킬 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 이를 spring에서 지원해준다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Spring/core</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/27</guid>
      <comments>https://zeroone.tistory.com/27#entry27comment</comments>
      <pubDate>Mon, 31 Jan 2022 20:19:52 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] 2차원 배열 동서남북 움직이기</title>
      <link>https://zeroone.tistory.com/25</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;지도(그래프)에서 동서남북으로 움직이는 문제는 자주 출제되는 문제유형인 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 배열에서 상하좌우로 1칸씩 움직일 수 있고 배열의 범위를 초과하는 것을 다뤄야 할 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 2차원 배열 동서남북 움직이기를 템플릿으로 만들어 두면 좋을 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 R, L, U, D를 입력 받아 동서남북으로 움직이는 전형적인 문제의 답안이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;움직이는 좌표를 설정하고 공간을 벗어나는 경우를 continue로 무시하여 깔끔하게 코드를 작성하는 법이라 생각한다.&lt;/p&gt;
&lt;pre id=&quot;code_1643435033702&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

int r = 1, c = 1;
int n;
string plans;

// 동, 서, 남, 북 방향
int dr[4] = {0, 0, 1, -1};
int dc[4] = {1, -1, 0, 0};
char move_types[4] = {'R', 'L', 'D', 'U'};

int main(void) {
    cin &amp;gt;&amp;gt; n;
    cin.ignore();
    getline(cin, plans);

    // 이동 계획을 하나씩 확인
    for (int i = 0; i &amp;lt; plans.size(); i++) {
        char plan = plans[i];

        // 이동 후 좌표 구하기
        int tr = r, tc = c;
        for (int j = 0; j &amp;lt; 4; j++) {
            if (plan == move_types[j]) {
                tr += dr[j];
                tc += dc[j];
            }
        }

        // 공간을 벗어나는 경우 무시
        if (tr &amp;lt; 1 || tr &amp;gt; n || tc &amp;lt; 1 || tc &amp;gt; n) {
            continue;
        }

        r = tr;
        c = tc;
    }

    cout &amp;lt;&amp;lt; r &amp;lt;&amp;lt; &quot; &quot; &amp;lt;&amp;lt; c &amp;lt;&amp;lt; &quot;\n&quot;;

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/25</guid>
      <comments>https://zeroone.tistory.com/25#entry25comment</comments>
      <pubDate>Sat, 29 Jan 2022 14:46:05 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] 순열과 조합</title>
      <link>https://zeroone.tistory.com/24</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;C++에서는 순열과 조합을 각각 next_permutation, prev_permutation을 이용해 쉽게 구할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;next_permutation&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;algorithm&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;헤더에는 n개의 원소의 순열을 구할 수 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;next_permutation&lt;/b&gt;&lt;/span&gt;이라는 함수가 있습니다. 기본적 문법은 다음과 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;1&lt;/div&gt;
&lt;div&gt;2&lt;/div&gt;
&lt;div&gt;3&lt;/div&gt;
&lt;div&gt;4&lt;/div&gt;
&lt;div&gt;5&lt;/div&gt;
&lt;div&gt;6&lt;/div&gt;
&lt;div&gt;7&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;div&gt;
&lt;div&gt;&lt;span style=&quot;color: #999999;&quot;&gt;//&amp;nbsp;default&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #4be6fa;&quot;&gt;bool&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color: #ff3399;&quot;&gt;next_permutation&lt;/span&gt;&amp;nbsp;(BidirectionalIterator&amp;nbsp;first,&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BidirectionalIterator&amp;nbsp;last);&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #999999;&quot;&gt;//&amp;nbsp;custom&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;&lt;span style=&quot;color: #4be6fa;&quot;&gt;bool&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;color: #ff3399;&quot;&gt;next_permutation&lt;/span&gt;&amp;nbsp;(BidirectionalIterator&amp;nbsp;first,&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;BidirectionalIterator&amp;nbsp;last,&amp;nbsp;Compare&amp;nbsp;comp);&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;http://colorscripter.com/info#e&quot;&gt;&lt;span style=&quot;background-color: #4f4f4f; color: #ffffff;&quot;&gt;cs&lt;/span&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next_permutation은 순열을 구할 컨테이너(쉽게 말해 배열)의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;시작과 끝 iterator&lt;/b&gt;를 인자로 받습니다. 만약 해당 컨테이너에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다음 순열&lt;/b&gt;이 존재하면 그 컨테이너의 원소를 해당 순열 순서로 바꾸고 true를 반환하고, 다음 순열이 없다면 false를 반환합니다. 위 코드의 custom에서 볼 수 있듯이 비교 함수 comp를 인자로 넘기는 것도 가능합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;next_permutation을 사용할 때는 몇 가지&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;주의할 점&lt;/b&gt;이 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;오름차순으로 정렬된 값&lt;/b&gt;을 가진 컨테이너로만 사용가능합니다.&lt;/li&gt;
&lt;li&gt;default로 operator &amp;lt; 를 사용해 순열을 생성합니다. 즉&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;오름차순으로 순열을 생성&lt;/b&gt;합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;중복이 있는 원소들은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중복을 제외&lt;/b&gt;하고 순열을 만들어줍니다.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번의 예시를 들자면 {0, 0, 1}과 같은 배열의 순열을 구한다면 중복을 제외한&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{0, 0, 1}, {0, 1, 0}, {1, 0, 0}이 됩니다. 이를 이용해 조합(Combination)을 구할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;출처:&amp;nbsp;&lt;a href=&quot;https://mjmjmj98.tistory.com/38&quot;&gt;https://mjmjmj98.tistory.com/38&lt;/a&gt;&amp;nbsp;[Live passionate ]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;순열 - 중복 포함하지 않음&amp;gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1642832021591&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using namespace std;

vector&amp;lt;int&amp;gt; v{2, 1, 3};

int main(void) {

    // 1. next_permutation 사용을 위한 v 오름차순 정렬
    sort(v.begin(), v.end());

    // 2. 오름차순으로 정렬된 순열 출력
    do {
        for (auto it = v.begin(); it != v.end(); it++) {
            cout &amp;lt;&amp;lt; *it &amp;lt;&amp;lt; &quot; &quot;;
        }
        cout &amp;lt;&amp;lt; endl;
    }
    while (next_permutation(v.begin(), v.end()));

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;조합 - 중복 포함하지 않음&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1642832066391&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;functional&amp;gt;

using namespace std;

vector&amp;lt;int&amp;gt; v{2, 1, 3};
vector&amp;lt;int&amp;gt; t{1, 1, 0};

int main(void) {

    // 1. prev_permutation 사용을 위한 t 내림차순 정렬
    sort(t.begin(), t.end(), greater&amp;lt;int&amp;gt;());

    // 2. 내림차순으로 정렬된 데이터를 받아서 순열로 뽑고 그 부분만 v에서 뽑아내 조합으로 만들기
    do {
        for (int i = 0; i &amp;lt; v.size(); i++) {
            if (t[i]) {
                cout &amp;lt;&amp;lt; v[i] &amp;lt;&amp;lt; &quot; &quot;;
            }
        }
        cout &amp;lt;&amp;lt; endl;
    }
    while (prev_permutation(t.begin(), t.end()));

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;do-while은 쓰면 안 좋다지만, 위의 경우는 예외로 쓰도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로, next_permutation, prev_permutation 함수는 터미널에서는 기본 제공되지만, 백준과 같은 사이트에서 사용하려면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#include &amp;lt;algorithm&amp;gt;을 해줘야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간복잡도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- next_permutation 자체가 O(n)이고 nPr 자체는 O(n!) 이므로 위 템플릿처럼 순열 조합을 구현하면 O(n*n!)이 된다.&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/24</guid>
      <comments>https://zeroone.tistory.com/24#entry24comment</comments>
      <pubDate>Sat, 22 Jan 2022 15:42:16 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] Prefix Sum, 구간 합 계산</title>
      <link>https://zeroone.tistory.com/23</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Prefix Sum : 여러 개의&amp;nbsp;누적합, 구간합을 묻는 쿼리에 대해 효율적인 알고리즘&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;누적합 : [0, Right] 구간의 합&lt;/li&gt;
&lt;li&gt;구간합 : [Left, Right] 구간의 합&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 구간합을 구하는 것이 O(N)이고 구간합을 구하라는  M개의 쿼리가  들어온다면 시간복잡도는 O(NM)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N = 1,000,000 이고 M = 1,000,000이라면 시간복잡도가 너무 안좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우 사용하는 것이 Prefix Sum 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;누적합을 구해놓고 누적합 간에 -연산을 하면 구간합이기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시간복잡도 : O(N+M)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 동작과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1) N개의 수에 대하여 접두사 합(Prefix Sum)을 계산하여 배열 P에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 2) 매 M개의 쿼리 정보 [L, R]을 확인할 때 구간 합은 P[R]-P[L-1]이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ▪️ 이때, P[0] 에 0을 넣고 L &amp;gt;= 1 을 만들면 코드가 간결해진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1642666766674&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

int n = 5;
vector&amp;lt;int&amp;gt; data = {10, 20, 30, 40, 50};
vector&amp;lt;int&amp;gt; prefix_sum;

int main(void) {
    // 첫 배열 0 대입
    prefix_sum.push_back(0);

    int sum_value = 0;
    for (auto d : data) {
        sum_value += d;
        prefix_sum.push_back(sum_value);
    }

    int left = 3;
    int right = 4;
    cout &amp;lt;&amp;lt; prefix_sum[right] - prefix_sum[left-1] &amp;lt;&amp;lt; endl;


    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 위 코드는 90도 회전할 때마다 vector를 선언해 heap영역에 계속  쌓이게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러번 돌리면 메모리 관점에서 좋지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기 때문에 4번이 넘어가는 회전은 4로 나눈 나머지만 회전하는 등 사용에 주의가 필요하다.&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/23</guid>
      <comments>https://zeroone.tistory.com/23#entry23comment</comments>
      <pubDate>Thu, 20 Jan 2022 17:19:35 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] 투 포인터</title>
      <link>https://zeroone.tistory.com/22</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;투 포인터(Two Pointer) 알고리즘 : 리스트에 순차적으로 접근해야 할 때 2개의 점의 위치를 기록하면서 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;투 포인터는 다음 2가지 케이스가 대표적인 문제 유형이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 특정한 합(M)을 가지는 부분 연속 수열 찾기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 시간복잡도 : O(N) { O(2*N)}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 동작과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 1) 시작점(s)와 끝점(e)를 첫 번째 원소의 인덱스(0)로 지정한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 2) s부터 e까지 현재 부분합이 특정한 합(M)과 같다면 카운트한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 3) s부터 e까지 현재 부분합이 특정한 합(M)보다 작다면 e를 1 증가시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 4) s부터 e까지 현재 부분합이 특정합 합(M)보다 크다면 s를 1 증가시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 5) 모든 경우를 확인할 떄까지 2)번부터 4)까지의 과정을 반복한다.&lt;/p&gt;
&lt;pre id=&quot;code_1642661566616&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

int n = 5, m = 5; // 데이터의 개수 n, 찾고자 하는 부분합 m

int arr[] = {1, 2, 3, 2, 5};

int main(void) {
    int cnt = 0;
    int interval_sum = 0;
    int e = 0;

    // start를 차례때로 증가시키며 반복
    for (int s = 0; s &amp;lt; n; s++) {
        // end를 가능한 만큼 이동시키기
        while (interval_sum &amp;lt; m &amp;amp;&amp;amp; e &amp;lt; n) {
            interval_sum += arr[e++];
        }

        // 부분합이 m일 때 카운트 증가
        if (interval_sum == m) {
            cnt++;
        }

        interval_sum -= arr[s];
    }

    cout &amp;lt;&amp;lt; cnt &amp;lt;&amp;lt; endl;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 정렬되어 있는 두 리스트의 정렬된 합집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 시간복잡도 : O(N+M) [N: a 크기, M: b 크기]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 동작과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 1) 정렬된 리스트 a와 b를 입력 받는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 2) 리스트 a에서 처리되지 않은 원소의 인덱스를 i로 지정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 3) 리스트 b에서 처리되지 않은 원소의 인덱스를 j로 지정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 4) a[i]와 b[j]중 저 작은 원소를 결과(result) 리스트에 담고 해당 리스트의 인덱스(i 또는 j)를 1 증가시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 5) a와 b에 처리할 원소가 없을 때까지 2) ~ 4) 과정을 반복한다.&lt;/p&gt;
&lt;pre id=&quot;code_1642661637682&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

// 사전에 정렬된 리스트 a, b 선언
int n = 3, m =4;
vector&amp;lt;int&amp;gt; a = {1, 3, 5};
vector&amp;lt;int&amp;gt; b = {2, 4, 6, 8};

int main(void) {
    int i = 0;
    int j = 0;
    // 리스트 a와 b의 모든 원소 담을 수 있는 결과 리스트
    vector&amp;lt;int&amp;gt; result;

    // 더 이상 리스트 a와 b에 처리할 원소가 없을 때까지 반복
    while (i &amp;lt; n || j &amp;lt; m) {
        // 리스트 b의 모든 원소가 처리되었거나, 리스트 a의 원소가 더 작을 경우
        if (j &amp;gt;= m || (i &amp;lt; n &amp;amp;&amp;amp; a[i] &amp;lt;= b[j])) {
            result.push_back(a[i++]);
        }
        // 처리되지 않은 리스트 b의 원소가 존재하고 리스트 a의 모든 원소가 처리되었거나, 리스트 b의 원소가 더 작을 경우
        else {
            result.push_back(b[j++]);
        }
    }

    for (int r : result) {
        cout &amp;lt;&amp;lt; r &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; endl;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2번 코드에서 while문 안의 if-else구문에 조건이 여러개 들어가는데 이 부분이 익숙하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익숙해지도록 하자.&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/22</guid>
      <comments>https://zeroone.tistory.com/22#entry22comment</comments>
      <pubDate>Thu, 20 Jan 2022 16:19:27 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] 2차원 리스트 90도 돌리기</title>
      <link>https://zeroone.tistory.com/21</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 리스트를 반시계방향으 90도 돌리는 함수 템플릿이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자주 사용될 것 같아 template으로 등록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;java, python을 이용한 코드는 많지만 c++을 이용한 코드는 찾기 어려워 따로 정리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시계방향으로 90도 돌리고 싶은 경우 해당함수를 3번 돌리자.&lt;/p&gt;
&lt;pre id=&quot;code_1642660420803&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; rotate_a_matrix_by_90_degree(vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; &amp;amp;graph)
{
    int row_len = graph.size();
    int col_len = graph[0].size();

    vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; res(col_len, vector&amp;lt;int&amp;gt;(row_len, 0));    

    for (int i = 0; i &amp;lt; row_len; i++) {
        for (int j = 0; j &amp;lt; col_len; j++) {
            res[col_len-j-1][i] = graph[i][j];
        }
    }
    
    return res;
}
int main(void) {

    vector&amp;lt;int&amp;gt; t1 = {1,2,3,4};
    vector&amp;lt;int&amp;gt; t2 = {5,6,7,8};
    vector&amp;lt;int&amp;gt; t3 = {9,10,11,12};

    vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; a = {t1, t2, t3};


    // 반시계 방향 90도 돌리기
    vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; b = rotate_a_matrix_by_90_degree(a);

    for (int i = 0; i &amp;lt; b.size(); i++) {
        for (int j = 0; j &amp;lt; b[i]. size(); j++) {
            cout &amp;lt;&amp;lt; b[i][j] &amp;lt;&amp;lt; &quot; &quot;;
        }
        cout &amp;lt;&amp;lt; endl;
    }

    // 시계 방향 90도 돌리기 =  반시계 방향 90도* 3 돌리기
    vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; c = rotate_a_matrix_by_90_degree(a);
    vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; d = rotate_a_matrix_by_90_degree(c);
    vector&amp;lt;vector&amp;lt;int&amp;gt; &amp;gt; e = rotate_a_matrix_by_90_degree(d);

    for (int i = 0; i &amp;lt; e.size(); i++) {
        for (int j = 0; j &amp;lt; e[i]. size(); j++) {
            cout &amp;lt;&amp;lt; e[i][j] &amp;lt;&amp;lt; &quot; &quot;;
        }
        cout &amp;lt;&amp;lt; endl;
    }

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/21</guid>
      <comments>https://zeroone.tistory.com/21#entry21comment</comments>
      <pubDate>Thu, 20 Jan 2022 15:39:22 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] 소수의 판별</title>
      <link>https://zeroone.tistory.com/20</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1. 가장 기본적인 소수 판별&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 시간복잡도 : O(N)&lt;/p&gt;
&lt;pre id=&quot;code_1642659493983&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

int x;

bool isPrime(int x) {
    for (int i = 2; i &amp;lt; x; i++) {
        if (x % i == 0) {
            return false;
        }
    }
    return true;
}

int main(void) {
    cin &amp;gt;&amp;gt; x;

    cout &amp;lt;&amp;lt; isPrime(x) &amp;lt;&amp;lt; endl;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 성능을 높인 소수 판별&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 시간복잡도 : O(sqrt(N))&lt;/p&gt;
&lt;pre id=&quot;code_1642659543686&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;cmath&amp;gt;

using namespace std;

int x;

bool isPrime(int x) {
    for (int i = 2; i &amp;lt;= sqrt(x); i++) {
        if (x % i == 0) {
            return false;
        }
    }
    return true;
}

int main(void) {
    cin &amp;gt;&amp;gt; x;

    cout &amp;lt;&amp;lt; isPrime(x) &amp;lt;&amp;lt; endl;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 에라토스테네스의 체(성능 업그레이드 버전)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 시간복잡도 : O(N*log(log(N)))&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 다수의 소수를 구할 경우에 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 동작 과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 1) 2부터 N까지의 모든 자연수를 나열한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 2) 남은 수 중에서 아직 처리하지 않은 가장 작은 수 i를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 3) 남은 수 중에서 i의 배수를 모두 제거한다.(i를 제거하지는 않는다, N까지의 i의 배수 제거)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 4) 더 이상 반복할 수 없을 때까지 2), 3) 과정을 반복한다.&lt;/p&gt;
&lt;pre id=&quot;code_1642659953528&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;cmath&amp;gt;

using namespace std;

int n = 1000;
vector&amp;lt;bool&amp;gt; prime(n+1, true);

// 에라토스테네스의 체
void makePrime(int n) {
    for (int i = 2; i &amp;lt;= sqrt(n); i++) {
        if (prime[i]) {
            int j = 2;
            while (i * j &amp;lt;= n) {
                prime[i * j] = false;
                j++;
            }
        }
    }
}

int main(void) {

    makePrime(n);

    // 0, 1 은 소수가 아니다.
    prime[0] = false;
    prime[1] = false;

    for (int i = 0; i &amp;lt;= n; i++) {
        if (prime[i])
            cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; endl;

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총정리 : 다수의 소수를 판별할 땐 3번[O(N*log(log(N)))]을, 적은 수의 소수를 판별할 땐 2번[O(sqrt(N))]을 사용하자.&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/20</guid>
      <comments>https://zeroone.tistory.com/20#entry20comment</comments>
      <pubDate>Thu, 20 Jan 2022 15:28:54 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][오답노트][이코테] 45. 최종 순위</title>
      <link>https://zeroone.tistory.com/19</link>
      <description>&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제&lt;/h2&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_description&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해 ACM-ICPC 대전 인터넷 예선에는 총 n개의 팀이 참가했다. 팀은 1번부터 n번까지 번호가 매겨져 있다. 놀랍게도 올해 참가하는 팀은 작년에 참가했던 팀과 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;올해는 인터넷 예선 본부에서는 최종 순위를 발표하지 않기로 했다. 그 대신에 작년에 비해서 상대적인 순위가 바뀐 팀의 목록만 발표하려고 한다. (작년에는 순위를 발표했다) 예를 들어, 작년에 팀 13이 팀 6 보다 순위가 높았는데, 올해 팀 6이 팀 13보다 순위가 높다면, (6, 13)을 발표할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;창영이는 이 정보만을 가지고 올해 최종 순위를 만들어보려고 한다. 작년 순위와 상대적인 순위가 바뀐 모든 팀의 목록이 주어졌을 때, 올해 순위를 만드는 프로그램을 작성하시오. 하지만, 본부에서 발표한 정보를 가지고 확실한&amp;nbsp;올해 순위를 만들 수 없는 경우가 있을 수도 있고, 일관성이 없는 잘못된 정보일 수도 있다. 이 두 경우도 모두 찾아내야 한다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;입력&lt;/h2&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_input&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫째 줄에는 테스트 케이스의 개수가 주어진다. 테스트 케이스는 100개를 넘지 않는다. 각 테스트 케이스는 다음과 같이 이루어져 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;팀의 수 n을 포함하고 있는 한 줄. (2 &amp;le; n &amp;le; 500)&lt;/li&gt;
&lt;li&gt;n개의 정수 ti를 포함하고 있는 한 줄. (1 &amp;le; ti&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;le; n) ti는 작년에 i등을 한 팀의 번호이다. 1등이 가장 성적이 높은 팀이다. 모든 ti는 서로 다르다.&lt;/li&gt;
&lt;li&gt;상대적인 등수가 바뀐 쌍의 수 m (0 &amp;le; m &amp;le; 25000)&lt;/li&gt;
&lt;li&gt;두 정수 ai와 bi를 포함하고 있는 m줄. (1 &amp;le; ai&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt; bi&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;le; n) 상대적인 등수가 바뀐 두 팀이 주어진다. 같은 쌍이 여러 번 발표되는 경우는 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;출력&lt;/h2&gt;
&lt;/div&gt;
&lt;div id=&quot;problem_output&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 테스트 케이스에 대해서 다음을 출력한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;n개의 정수를 한 줄에 출력한다. 출력하는 숫자는 올해 순위이며, 1등팀부터 순서대로 출력한다. 만약, 확실한 순위를 찾을 수 없다면 &quot;?&quot;를 출력한다. 데이터에 일관성이 없어서 순위를 정할 수 없는 경우에는 &quot;IMPOSSIBLE&quot;을 출력한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;느낀점&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그래프 문제를 풀면서 어렵다고 느낀 부분은 말로 풀어진 문제를 그래프로 스스로 해석하여 풀어내는 사고방식이다.&lt;/li&gt;
&lt;li&gt;이 문제는 '정해진 우선순위에 맞게 전체 팀들의 순서를 나열해야 한다'는 점에서 '위상정렬'을 떠올릴 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;'각 팀'들을 '노드'로 작년 순위를 토대로 '팀 간 우선순위'를 방향성 간선으로 그린다.&lt;/li&gt;
&lt;li&gt;이후 제시해주는 바뀐 팀간 우선순위를 토대로 간선의 방향을 바꿔 그린다.&lt;/li&gt;
&lt;li&gt;이후 위상정렬을 통해 그래프를 그릴 수 있는지 확인해본다.&lt;/li&gt;
&lt;li&gt;위상정렬은 2가지 주의사항이 있다.&lt;br /&gt;1. 사이클이 발생하는 경우&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;=&amp;gt; 일관성이 없다.&lt;br /&gt;2. 위상정렬의 경우의 수가 2가지 이상인 경우&amp;nbsp; &amp;nbsp; =&amp;gt; 확실한 순위를 찾을 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;원본문제 :&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/3665&quot;&gt;https://www.acmicpc.net/problem/3665&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1642330133504&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;3665번: 최종 순위&quot; data-og-description=&quot;올해 ACM-ICPC 대전 인터넷 예선에는 총 n개의 팀이 참가했다. 팀은 1번부터 n번까지 번호가 매겨져 있다. 놀랍게도 올해 참가하는 팀은 작년에 참가했던 팀과 동일하다. 올해는 인터넷 예선 본부에&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/3665&quot; data-og-url=&quot;https://www.acmicpc.net/problem/3665&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Bkiqc/hyM6NerXGv/GaNdX6b1wPTNvvpHLY6Cp0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/3665&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/3665&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Bkiqc/hyM6NerXGv/GaNdX6b1wPTNvvpHLY6Cp0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;3665번: 최종 순위&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;올해 ACM-ICPC 대전 인터넷 예선에는 총 n개의 팀이 참가했다. 팀은 1번부터 n번까지 번호가 매겨져 있다. 놀랍게도 올해 참가하는 팀은 작년에 참가했던 팀과 동일하다. 올해는 인터넷 예선 본부에&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1642330921812&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;

using namespace std;

int t;
int n;
int m;
int indegree[501];
bool graph[501][501];

void topologySort() {
    queue&amp;lt;int&amp;gt; q;

    for (int i = 1; i &amp;lt;= n; i++) {
        if (indegree[i] == 0) {
            q.push(i);
        } 
    }

    vector&amp;lt;int&amp;gt; ans;
    bool not_certain = false;
    bool cycle = false;
    for (int i = 0; i &amp;lt; n; i++) {
        if (q.size() == 0) {
            cycle = true;
            break;
        }
        if (q.size() &amp;gt; 1) {
            not_certain = true;
            break;
        }

        int now = q.front();
        ans.push_back(now);
        q.pop();

        int chk_double = 0;
        for (int j = 1; j &amp;lt;= n; j++) {
            if (graph[now][j]) {
                indegree[j]--;
                if (indegree[j] == 0) {
                    q.push(j);
                }
            }
        }
    }

    if (cycle) {
        cout &amp;lt;&amp;lt; &quot;IMPOSSIBLE&quot; &amp;lt;&amp;lt; endl;
        return;
    }
    if (not_certain) {
        cout &amp;lt;&amp;lt; &quot;?&quot; &amp;lt;&amp;lt; endl;
        return;
    }
    
    for (int i = 0; i &amp;lt; n; i++) {
        cout &amp;lt;&amp;lt; ans[i] &amp;lt;&amp;lt; &quot; &quot;;    
    }
    cout &amp;lt;&amp;lt; endl;

}

int main(void) {
    cin &amp;gt;&amp;gt; t;
    for (int i = 0; i &amp;lt; t; i++) {
        cin &amp;gt;&amp;gt; n;

        fill(indegree, indegree+501, 0);
        fill(graph[0], graph[0]+501*501, false);

        vector&amp;lt;int&amp;gt; v;
        for (int j = 0; j &amp;lt; n; j++) {
            int a;
            cin &amp;gt;&amp;gt; a;
            v.push_back(a);
        }

        for (int j = 0; j &amp;lt; n; j++) {
            for (int k = j+1; k &amp;lt; n; k++) {
                graph[v[j]][v[k]] = true;
                indegree[v[k]]++;
            }
        }

        cin &amp;gt;&amp;gt; m;
        for (int j = 0; j &amp;lt; m; j++) {
            int  a, b;
            cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
            if (graph[a][b]) {
                indegree[a]++;
                indegree[b]--;
            }
            if (graph[b][a]) {
                indegree[a]--;
                indegree[b]++;
            }
            swap(graph[a][b], graph[b][a]);
        }

        topologySort();
    }
    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/오답노트</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/19</guid>
      <comments>https://zeroone.tistory.com/19#entry19comment</comments>
      <pubDate>Sun, 16 Jan 2022 20:02:11 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][오답노트][이코테] 42. 탑승구</title>
      <link>https://zeroone.tistory.com/18</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;문제&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;공항에는 G개의 탑승구가 있으며, 각각의 탑승구는 1번부터 G번까지 번호로 구분된다. 공항에는 P개의 비행기가 차례대로 도착할 예정이며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span data-mathml=&quot;&amp;lt;math xmlns=&amp;quot;http://www.w3.org/1998/Math/MathML&amp;quot;&amp;gt;&amp;lt;mi&amp;gt;i&amp;lt;/mi&amp;gt;&amp;lt;/math&amp;gt;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;번째 비행기를 1번부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span data-mathml=&quot;&amp;lt;math xmlns=&amp;quot;http://www.w3.org/1998/Math/MathML&amp;quot;&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;mi&amp;gt;g&amp;lt;/mi&amp;gt;&amp;lt;mi&amp;gt;i&amp;lt;/mi&amp;gt;&amp;lt;/msub&amp;gt;&amp;lt;/math&amp;gt;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;gi&lt;/span&gt;&lt;/span&gt;(1 &amp;lt;=&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span data-mathml=&quot;&amp;lt;math xmlns=&amp;quot;http://www.w3.org/1998/Math/MathML&amp;quot;&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;mi&amp;gt;g&amp;lt;/mi&amp;gt;&amp;lt;mi&amp;gt;i&amp;lt;/mi&amp;gt;&amp;lt;/msub&amp;gt;&amp;lt;/math&amp;gt;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;gi&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;= G) 탑승구 중 하나에 영구적으로 도킹하려 한다. 이 때, 다른 비행기가 도킹하지 않은 탑승구에만 도킹이 가능하다. 또한 P개의 비행기를 순서대로 도킹하다가 만약에 어떠한 탑승구에도 도킹할 수 없는 비행기가 나오는 경우, 그 시점에서 공항의 운행을 중단한다. 공항의 관리자는 최대한 많은 비행기를 공항에 도킹하고자 한다. 비행기를 최대 몇 대 도킹할 수 있는지를 출력해라&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;입력&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;첫째 줄에는 탑승구의 수 G(1 &amp;lt;= G &amp;lt;= 100,000)가 주어진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;둘째 줄에는 비행기의 수 P(1 &amp;lt;= P &amp;lt;= 100,000)가 주어진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음 P개의 줄에는 각 비행기가 도킹할 수 있는 탑승구의 정보&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span data-mathml=&quot;&amp;lt;math xmlns=&amp;quot;http://www.w3.org/1998/Math/MathML&amp;quot;&amp;gt;&amp;lt;mi&amp;gt;g&amp;lt;/mi&amp;gt;&amp;lt;/math&amp;gt;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;(1 &amp;lt;=&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span data-mathml=&quot;&amp;lt;math xmlns=&amp;quot;http://www.w3.org/1998/Math/MathML&amp;quot;&amp;gt;&amp;lt;mi&amp;gt;g&amp;lt;/mi&amp;gt;&amp;lt;/math&amp;gt;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;= G)가 주어진다. 이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span data-mathml=&quot;&amp;lt;math xmlns=&amp;quot;http://www.w3.org/1998/Math/MathML&amp;quot;&amp;gt;&amp;lt;mi&amp;gt;i&amp;lt;/mi&amp;gt;&amp;lt;/math&amp;gt;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;번째 비행기가 1번부터&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span data-mathml=&quot;&amp;lt;math xmlns=&amp;quot;http://www.w3.org/1998/Math/MathML&amp;quot;&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;mi&amp;gt;g&amp;lt;/mi&amp;gt;&amp;lt;mi&amp;gt;i&amp;lt;/mi&amp;gt;&amp;lt;/msub&amp;gt;&amp;lt;/math&amp;gt;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;gi&lt;/span&gt;&lt;/span&gt;번째(1 &amp;lt;=&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span data-mathml=&quot;&amp;lt;math xmlns=&amp;quot;http://www.w3.org/1998/Math/MathML&amp;quot;&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;mi&amp;gt;g&amp;lt;/mi&amp;gt;&amp;lt;mi&amp;gt;i&amp;lt;/mi&amp;gt;&amp;lt;/msub&amp;gt;&amp;lt;/math&amp;gt;&quot;&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;g&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;gi&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;= G) 탑승구 중 하나에 도킹할 수 있다는 의미이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;출력&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;첫째 줄에 도킹할 수 있는 비행기의 최대 개수를 출력해라.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;느낀점&lt;/span&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 문제는 처음에 단순 구현이 떠올랐다. 그래프 카테고리에 있음에도..이 문제는 추가적인 테스트케이스가 제공되지 않아 정답임을 확인할 수는 없었다. 아마 틀렸을 것이다. 그리고 답안을 보니 너무 쉽다.&lt;/li&gt;
&lt;li&gt;또한 union-find가 서로소를 판별하기 위한 알고리즘으로 대표적이지만 집합의 제한을 하기에도 사용됨을 깨닫게 해준 문제다.&lt;/li&gt;
&lt;li&gt;이 문제를 다시 푼다고 해도 union-find를 떠올릴지 의아하다...&lt;/li&gt;
&lt;li&gt;'공항'을 root탑승구를 가진 하나의 '집합'으로 바라보고 하나의 비행기가 탑승구에 집합할 때마다 union 한다.&lt;/li&gt;
&lt;li&gt;&quot;더 이상 union할 수 있는 탑승구가 없다 == 0번 탑승구에 도킹해야 한다&quot; 가 나오면 더이상 도킹할 수 없으므로&amp;nbsp; 공항의 운행을 중단한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1642330017173&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

int g, p;
int parent[100001];

int findParent(int a) {
    if (parent[a] != a) {
        parent[a] = findParent(parent[a]);
    }
    return parent[a];
}

void unionParent(int a, int b) {
    a = findParent(a);
    b = findParent(b);

    if (a &amp;lt; b) {
        parent[b] = a;
    }
    else {
        parent[a] = b;
    }
}

int main(void) {
    cin &amp;gt;&amp;gt; g &amp;gt;&amp;gt; p;

    for (int i = 1; i &amp;lt;= g; i++) {
        parent[i] = i;
    }

    int ans = 0;
    for (int i = 0; i &amp;lt; p; i++) {
        int a;
        cin &amp;gt;&amp;gt; a;
        int root = findParent(a);
        if (root != 0) {
            ans++;
            unionParent(root, root-1);
        }
        else {
            break;
        }
    }

    cout &amp;lt;&amp;lt; ans &amp;lt;&amp;lt; endl;


    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/오답노트</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/18</guid>
      <comments>https://zeroone.tistory.com/18#entry18comment</comments>
      <pubDate>Sun, 16 Jan 2022 19:47:07 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] 위상 정렬(Topology Sort)</title>
      <link>https://zeroone.tistory.com/17</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;위상정렬이란, 방향 그래프의 모든 노드를 '방향성에 거스르지 않도록 순서대로 나열하는 것'이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키 포인트는 '진입차수(indegree)'이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 진입차수가 0인 노드를 큐에 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 큐가 빌 때까지 다음의 과정을 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;2-1) 큐에서 원소를 꺼내 해당 노드에서 출발하는 간선을 그래프에서 제거한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;2-2) 새롭게 진입차수가 0이 된 노드를 큐에 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위상정렬의 시간복잡도는 O(V+E)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;차례대로 모든 노드를 확인하면서 해당노드에서 출발하는 간선을 제거한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 노드와 간선을 전부 한번씩 탐색한다고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐에 I/O하는 시간은  V와 같으므로 무시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주의사항은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 위상정렬 도중, 사이클이 발생할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 위상정렬로 나열한 경우의 수가 2가지 이상일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1642239043672&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;queue&amp;gt;

using namespace std;

// 노드의 개수(v)와 간선의 개수(e)
// 노드의 개수는 최대 100000개 라고 가정
int v, e;
// 모든 노드에 대한 진입차수는 0으로 초기화
int indegree[100001];
// 각 노드에 연결된 간선 정보를 담기위한 인접 리스트 초기화
vector&amp;lt;int&amp;gt; graph[100001];

// 위상 정렬 함수
void topologySort() {
    vector&amp;lt;int&amp;gt; result; // 알고리즘 수행 결과를 담을 리스트
    queue&amp;lt;int&amp;gt; q; // 진입차수 0인 노드를 넣을 큐


    // 처음 시작할 때는 진입차수 0인 노드를 큐에 삽입
    for (int i = 1; i &amp;lt;= v; i++) {
        if (indegree[i] == 0) {
            q.push(i);
        }
    }

    // 큐가 빌때까지 반복
    while (!q.empty()) {
        // 큐에서 원소 꺼내기
        int now = q.front();
        q.pop();
        result.push_back(now);

        // 해당 원소와 연결된 노드들의 진입차수에서 1 빼기
        for (int e : graph[now]) {
            indegree[e]--;    
            // 새롭게 진입차수가 0이 되는 노드 큐에 삽입
            if (indegree[e] == 0) {
                q.push(e);    
            }
        }
    }

    // 위상 정렬을 수행한 결과 출력
    for (int x: result) {
        cout &amp;lt;&amp;lt; x &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; endl;

}

int main(void) {
    cin &amp;gt;&amp;gt; v &amp;gt;&amp;gt; e;
    // 방향그래프의 모든 간선 정보를 입력 받기
    for (int i = 0; i &amp;lt; e; i++) {
        int a, b;
        cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
        graph[a].push_back(b); // 정점 a에서 b로 이동 가능
        // 진입 차수를 1 증가
        indegree[b] += 1;
    }

    topologySort();

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/17</guid>
      <comments>https://zeroone.tistory.com/17#entry17comment</comments>
      <pubDate>Sat, 15 Jan 2022 18:30:59 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] 크루스칼 알고리즘</title>
      <link>https://zeroone.tistory.com/16</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;  신장트리(Spanning Tree) : 하나의 그래프가 있을 때 모든 노드를 포함하면서 사이클이 존재하지 않는 부분 그래프&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크루스칼 알고리즘 : 신장 트리 중에서 최소 비용으로 만들 수 있는 신장 트리를 찾는 알고리즘, Union-FInd를 이용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 간선 데이터를 비용에 따라 오름차순으로 정렬한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 간선을 하나씩 확인하며 현재의 간선이 사이클을 발생시키는지 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 2-1) 사이클 발생하지 않는 경우 : 최소 신장트리에 포함시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 2-2) 사이클이 발생하는 경우 : 최소 신장트리에 포함시키지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 모든 간선에 대하여 2번의 과정을 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1641221719748&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;tuple&amp;gt;

using namespace std;

// 노드의 개수(v)와 간선(e)의 개수
// 노드의 개수는 최대 100000개라고 가정
int v, e;
int parent[100001];

// 특정 원소가 속한 집합을 찾기
int findParent(int x) {
     if (parent[x] != x) {
         parent[x] = findParent(parent[x]);
     }
     return parent[x];
 }

// 두 원소가 속한 집합을 합치기
void unionParent(int x, int y) {
    x = findParent(x);
    y = findParent(y);

    if (x &amp;lt; y) {
        parent[y] = x;
    }
    else {
        parent[x] = y;
    }
}

int main(void) {
    vector&amp;lt;tuple&amp;lt;int, int, int&amp;gt; &amp;gt; edge;

    cin &amp;gt;&amp;gt; v &amp;gt;&amp;gt; e;

    // 부모테이블 상에서, 부모를 자기 자신으로 초기화
    for (int i = 1; i &amp;lt;= v; i++) {
        parent[i] = i;
    }

    // union 연산을 각각 수행
    for (int i = 0; i &amp;lt; e; i++) {
        int a, b, d;
        cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b &amp;gt;&amp;gt; d;
        edge.push_back(make_tuple(d, a, b));
    }

    // 간선 거리별 오름차순 정렬
    sort(edge.begin(), edge.end()); // greater&amp;lt;int&amp;gt;()

    int sum = 0;
    for (auto t : edge) {
        int a, b, d;
        tie(d, a, b) = t;
        if (findParent(a) != findParent(b)) {
            unionParent(a, b);
            sum += d;
        }
    }
    
    cout &amp;lt;&amp;lt; sum &amp;lt;&amp;lt; endl;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  유의사항 : template에서 사용한 tuple은 c++11버전에서만 사용할 수 있다.&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/16</guid>
      <comments>https://zeroone.tistory.com/16#entry16comment</comments>
      <pubDate>Mon, 3 Jan 2022 23:56:49 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] 서로소 집합(Disjoint Set), Union-Find</title>
      <link>https://zeroone.tistory.com/15</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;서로소 집합(Disjoint Set) : 공통 원소가 없는 두 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서로소 부분 집합들로 나누어진 원소들을 데이터를 처리하기 위한 자료구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;union과 find 2개의 연사으로 조작할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리 자료구조로 표현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;✔️union-find 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. union(합집합)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;1) A와 B의 부모노드 A', B'을 각각 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;2) A'를 B'의 부모 노드로 설정한다. (if. A' &amp;lt; B')&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. find(부모노드 찾기)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 루트 노드 탐색&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;1번째 소스 : 수정 전&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1641135048529&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

// 노드의 개수(v)와 간선(e)의 개수
// 노드의 개수는 최대 100000개라고 가정
int v, e;
int parent[100001];

// 특정 원소가 속한 집합을 찾기
int findParent(int x) {
    if (parent[x] != x) {
        return findParent(parent[x]);
    }
    return x;
}

// 두 원소가 속한 집합을 합치기
void unionParent(int x, int y) {
    x = findParent(x);
    y = findParent(y);

    if (x &amp;lt; y) {
        parent[y] = x;
    }
    else {
        parent[x] = y;
    }
}

int main(void) {

    cin &amp;gt;&amp;gt; v &amp;gt;&amp;gt; e;

    // 부모테이블 상에서, 부모를 자기 자신으로 초기화
    for (int i = 1; i &amp;lt;= v; i++) {
        parent[i] = i;
    }

    // union 연산을 각각 수행
    for (int i = 0; i &amp;lt; e; i++) {
        int a, b;
        cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
        unionParent(a, b);
    }

    // 각 원소가 속한 집할 출력
    cout &amp;lt;&amp;lt; &quot;각 원소가 속한 집합: &quot;;
    for (int i = 1 ; i &amp;lt;= v; i++) {
        cout &amp;lt;&amp;lt; findParent(i) &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; endl;

    // 부모 테이블 내용 출력
    cout &amp;lt;&amp;lt; &quot;부모 테이블: &quot;;
    for (int i = 1 ; i &amp;lt;= v; i++) {
        cout &amp;lt;&amp;lt; parent[i] &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; endl;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 소스는 노드의 개수(V)이고 union연산의 개수(M)일때, 시간복잡도가 O(VM)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 findParent 함수 부분을 다음과 같이 변경해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1641135216718&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int findParent(int x) {
    if (parent[x] != x) {
        parent[x] = findParent(parent[x]);
    }
    return parent[x];
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;수정 후에는 시간복잡도가&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;205&quot; data-origin-height=&quot;20&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFIo9S/btrplg64eZ8/HIgkdLHyktOZ7aV5fiJeq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFIo9S/btrplg64eZ8/HIgkdLHyktOZ7aV5fiJeq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFIo9S/btrplg64eZ8/HIgkdLHyktOZ7aV5fiJeq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFIo9S%2Fbtrplg64eZ8%2FHIgkdLHyktOZ7aV5fiJeq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;205&quot; height=&quot;20&quot; data-origin-width=&quot;205&quot; data-origin-height=&quot;20&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;이다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;해당 부분의 시간복잡도 증명은 다음에 다루겠다&lt;/u&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 최종 소스는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;2번째 소스 : 수정 후&amp;gt;&lt;/p&gt;
&lt;pre id=&quot;code_1641135254920&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;

using namespace std;

// 노드의 개수(v)와 간선(e)의 개수
// 노드의 개수는 최대 100000개라고 가정
int v, e;
int parent[100001];

// 특정 원소가 속한 집합을 찾기
int findParent(int x) {
     if (parent[x] != x) {
         parent[x] = findParent(parent[x]);
     }
     return parent[x];
 }

// 두 원소가 속한 집합을 합치기
void unionParent(int x, int y) {
    x = findParent(x);
    y = findParent(y);

    if (x &amp;lt; y) {
        parent[y] = x;
    }
    else {
        parent[x] = y;
    }
}

int main(void) {

    cin &amp;gt;&amp;gt; v &amp;gt;&amp;gt; e;

    // 부모테이블 상에서, 부모를 자기 자신으로 초기화
    for (int i = 1; i &amp;lt;= v; i++) {
        parent[i] = i;
    }

    // union 연산을 각각 수행
    for (int i = 0; i &amp;lt; e; i++) {
        int a, b;
        cin &amp;gt;&amp;gt; a &amp;gt;&amp;gt; b;
        unionParent(a, b);
    }

    // 각 원소가 속한 집할 출력
    cout &amp;lt;&amp;lt; &quot;각 원소가 속한 집합: &quot;;
    for (int i = 1 ; i &amp;lt;= v; i++) {
        cout &amp;lt;&amp;lt; findParent(i) &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; endl;

    // 부모 테이블 내용 출력
    cout &amp;lt;&amp;lt; &quot;부모 테이블: &quot;;
    for (int i = 1 ; i &amp;lt;= v; i++) {
        cout &amp;lt;&amp;lt; parent[i] &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; endl;

    return 0 ;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/15</guid>
      <comments>https://zeroone.tistory.com/15#entry15comment</comments>
      <pubDate>Sun, 2 Jan 2022 23:50:54 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] 플로이드 워셜 알고리즘</title>
      <link>https://zeroone.tistory.com/14</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;문제풀이 전략&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;-&amp;nbsp; 다익스트라&amp;nbsp; &amp;nbsp; : 한 지점에서 다른 특정 지점까지의 최단 경로를 구해야 하는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;1) 시간복잡도 O(E*logV), 다익스트라를 플로이드처럼 모든 지점에서 모든지점까지의 경로를 구할 경우 더 좋은 시간 성능으로 사용할&amp;nbsp; &amp;nbsp; &amp;nbsp;수 있을 것이라 예상 O(E*logV*V)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;2) 그래프 표현방법 : 인접리스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;3) 문제 접근 방식 : 그리드 알고리즘&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 플로이드 워셜 : 모든 지점에서 다른 모든 지점까지의 최단 경로를 모두 개야 하는 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;1) 시간복잡도 O(N^3)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;2) 그래프 표현방법 : 인접행렬&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;3) 문제 접근 방식 : 다이나믹 프로그래밍&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플로이드 워셜 알고리즘은 코드가 간결하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서&lt;span&gt; N&lt;/span&gt;이&lt;span&gt; &lt;/span&gt;작고&lt;span&gt; &lt;/span&gt;모든&lt;span&gt; &lt;/span&gt;지점에서&lt;span&gt; &lt;/span&gt;다른&lt;span&gt; &lt;/span&gt;모든&lt;span&gt; &lt;/span&gt;지점까지의&lt;span&gt; &lt;/span&gt;최단경로를&lt;span&gt; &lt;/span&gt;모두&lt;span&gt; &lt;/span&gt;구해야&lt;span&gt; &lt;/span&gt;하는경우&lt;span&gt; &lt;/span&gt;사용하자&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1640768325623&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

#define INF 1e9

using namespace std;

// 노드의 개수(n), 간선의 개수(m)
int n, m;
int graph[501][501];

int main(void)
{
    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; m;

    // 최단거리 테이블 전부 무한대로 초기화
    //fill(graph, graph + 500*500, INF);
    for (int i = 1; i &amp;lt;= 500; i++) {
        fill(graph[i], graph[i]+500, INF);
    }

    // 자기자신으로 가는 거리 0
    for (int i = 1; i &amp;lt;= 500; i++) {
        graph[i][i] = 0;
    }

    // 간선 입력 받아서 세팅
    int s, e, d;
    for (int i = 0; i &amp;lt; m; i++) {
        cin &amp;gt;&amp;gt; s &amp;gt;&amp;gt; e &amp;gt;&amp;gt; d;
        graph[s][e] = d;
    }

    for (int i = 1; i &amp;lt;= n; i++) {
        for (int j = 1; j &amp;lt;= n; j++) {
            for (int k = 1; k &amp;lt;= n; k++) {
                graph[j][k] = min(graph[j][k], graph[j][i] + graph[i][k]);
            }
        }
    }

    for (int i = 1; i &amp;lt;= n; i++) {
        for (int j = 1; j &amp;lt;= n; j++) {
            if (graph[i][j] == INF) {
                cout &amp;lt;&amp;lt; &quot;INF &quot;;
            }
            else {
                cout &amp;lt;&amp;lt; graph[i][j] &amp;lt;&amp;lt; &quot; &quot;;
            }
        }
        cout &amp;lt;&amp;lt; endl;
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/14</guid>
      <comments>https://zeroone.tistory.com/14#entry14comment</comments>
      <pubDate>Wed, 29 Dec 2021 17:58:52 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] Dijkstra 최단거리 탐색</title>
      <link>https://zeroone.tistory.com/13</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dijkstra 알고리즘을 이론 그대로 구현한 코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간복잡도는 O(V^2)이다.&lt;/p&gt;
&lt;pre id=&quot;code_1639813060979&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;

#define INF 1e9	// 무한을 의마하는 값으로 10억 설정

using namespace std;

int N, M, start;
vector&amp;lt;pair&amp;lt;int, int&amp;gt; &amp;gt; graph[10001];
int sd[10001];
bool visited[10001] = {false};

int getSmallestNode() {
	int min_value = INF;
	int min_index = 0;
	for (int i = 0; i &amp;lt; N; i++) {
		if (!visited[i] &amp;amp;&amp;amp; sd[i] &amp;lt; min_value) {
			min_index = i;
			min_value = sd[i];
		}
	}
	return min_index;
}

void dijkstra(int start) {
	// 시작 노드에 대해서 초기화
	sd[start] = 0;
	visited[start] = true;

	for (int i = 0; i &amp;lt; graph[start].size(); i++) {
		sd[graph[start][i].first] = sd[start] + graph[start][i].second;
	}

	for (int i = 0; i &amp;lt; N-1; i++) {
		//현재 노드와 연결된 다른 노드를 꺼내서, 방문 처리
		int now= getSmallestNode();	
		visited[now] = true;

		// 현재 노드의 연겱된 다른 노드를 확인
		for (int j = 0; j &amp;lt; graph[now].size(); j++) {
			int cost = sd[now] + graph[now][j].second;
			
			sd[graph[now][j].first] = min(sd[graph[now][j].first], cost);
		}
	}
	
}

int main(void)
{
	cin &amp;gt;&amp;gt; N &amp;gt;&amp;gt; M;
	cin &amp;gt;&amp;gt; start;

	for (int i = 0; i &amp;lt; M; i++) {
		int s, e, d;
		cin &amp;gt;&amp;gt; s &amp;gt;&amp;gt; e &amp;gt;&amp;gt; d;
		
		graph[s].push_back(make_pair(e, d));
	}	

	// 최단 거리 테이블을 모두 무한으로 초기화
	fill_n(sd, 10001, INF);
	
	// 다익스트라 알고리즘 수행
	dijkstra(start);

	for (int i = 1; i &amp;lt;= N; i++) {
		// 도달할 수 없는 경우, 무한(INFINITY)이라고 출력
		if (sd[i] == INF)
			cout &amp;lt;&amp;lt; &quot;INFINITY&quot; &amp;lt;&amp;lt; endl;
		else
			cout &amp;lt;&amp;lt; sd[i] &amp;lt;&amp;lt; endl;
	}

	return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dijkstra 알고리즘을 우선순위 큐를 이용해 시간복잡도를 줄인 코드다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 큐에 pair를 넣으면 pair의 first 값으로 내림차순 정렬을 하므로 pair의 first 값으로 노드간 거리 * -1 (-cost)을 넣어서 정렬한다. 그리고 pair의 second 값으로 도착 노드를 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위 큐에서 최단거리 노드를 뽑아 최단거리를 탐색한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간복잡도는 O(Elog(V))이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번보다 2번의 시간복잡도가 좋으므로 2번 코드만 보면 될 것 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1639813482884&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;iostream&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;utility&amp;gt;

#define INF 1e9

using namespace std;

int n, m, start;
vector&amp;lt;pair&amp;lt;int, int&amp;gt; &amp;gt; graph[10001];
int sd[100001];

void dijkstra(int start) {
    priority_queue&amp;lt;pair&amp;lt;int, int&amp;gt; &amp;gt; pq;

    // 시작 노드 거리 0 으로 우선순위 큐에 삽입
    pq.push(make_pair(0, start));
    sd[start] = 0;
    while(!pq.empty()) {
        // 가장 최단거리가 짧은 노드 뽑기
        int dist = -pq.top().first;
        int now = pq.top().second;
        pq.pop();

        // 처리된 적이 있는 노드 무시
        if (sd[now] &amp;lt; dist) continue;
        
        // 현재 노드와 연결된 다른 인접한 노드들을 확인
        for (int i = 0; i &amp;lt; graph[now].size(); i++) {
            int cost = dist + graph[now][i].second; // sd[now] == dist
            // 현재 노드를 거쳐서, 다른 노드로 가는 거리가 더 짧은 경우
            if (cost &amp;lt; sd[graph[now][i].first]) {
                sd[graph[now][i].first] = cost;
                pq.push(make_pair(-cost, graph[now][i].first));
            }
        }
    }
}

int main(void) 
{
    cin &amp;gt;&amp;gt; n &amp;gt;&amp;gt; m &amp;gt;&amp;gt; start;

    int s, e, d;
    for (int i = 0; i &amp;lt; m; i++) {
        cin &amp;gt;&amp;gt; s &amp;gt;&amp;gt; e &amp;gt;&amp;gt; d;
        graph[s].push_back(make_pair(e, d));
    }
       // 최단 거리 테이블을 모두 무한으로 초기화
    fill(sd, sd + 100001, INF);
    
    // 다익스트라 알고리즘을 수행
    dijkstra(start);

    // 모든 노드로 가기 위한 최단 거리를 출력
    for (int i = 1; i &amp;lt;= n; i++) {
        // 도달할 수 없는 경우, 무한(INFINITY)이라고 출력
        if (sd[i] == INF) {
            cout &amp;lt;&amp;lt; &quot;INFINITY&quot; &amp;lt;&amp;lt; '\n';
        }
        // 도달할 수 있는 경우 거리를 출력
        else {
            cout &amp;lt;&amp;lt; sd[i] &amp;lt;&amp;lt; '\n';
        }
    }

    return 0;
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/13</guid>
      <comments>https://zeroone.tistory.com/13#entry13comment</comments>
      <pubDate>Sat, 18 Dec 2021 16:45:07 +0900</pubDate>
    </item>
    <item>
      <title>[C++][STL] set과 unordered_set의 차이</title>
      <link>https://zeroone.tistory.com/12</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;set&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키들을 이진 탐색 트리를 기반으로 저장한다. 따라서 자동 정렬되는 컨테이너이고 탐색 시간은 O( log n ) 입니다. 삽입과 제거가 빈번해지면 느리다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;undorderd_set&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해쉬 테이블 기반으로 저장한다. 어떤 해쉬를 쓰느냐에 따라 다르겠지만, 같은 해쉬값을 중복적으로 저장한다면 최대 O(n)의 시간복잡도를 갖는다. 따라서 탐색시간이 기본적으론 O(1) 이지만 최악의 경우 O(n) 입니다. 자동 정렬되지 않는 set이다.&amp;nbsp;&amp;nbsp;버킷 때문에 메모리 사용량이 증가할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론 : 알고리즘 문제의 경우 최악의 복잡도가 중요하므로 기본 set을 이용하여 풀자. (이진탐색의 경우 set을 쓰면 좋다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++ STL</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/12</guid>
      <comments>https://zeroone.tistory.com/12#entry12comment</comments>
      <pubDate>Thu, 11 Nov 2021 23:19:02 +0900</pubDate>
    </item>
    <item>
      <title>[C++][STL] Hash Set</title>
      <link>https://zeroone.tistory.com/11</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Set은 중복을 찾기에 최적화된 자료구조다.&lt;/p&gt;
&lt;pre id=&quot;code_1634817977696&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#include &amp;lt;unordered_set&amp;gt;                // 0. include the library

int main() {
    // 1. initialize a hash set
    unordered_set&amp;lt;int&amp;gt; hashset;   
    // 2. insert a new key
    hashset.insert(3);
    hashset.insert(2);
    hashset.insert(1);
    // 3. delete a key
    hashset.erase(2);
    // 4. check if the key is in the hash set
    if (hashset.count(2) &amp;lt;= 0) {
        cout &amp;lt;&amp;lt; &quot;Key 2 is not in the hash set.&quot; &amp;lt;&amp;lt; endl;
    }
    // 5. get the size of the hash set
    cout &amp;lt;&amp;lt; &quot;The size of hash set is: &quot; &amp;lt;&amp;lt; hashset.size() &amp;lt;&amp;lt; endl; 
    // 6. iterate the hash set
    for (auto it = hashset.begin(); it != hashset.end(); ++it) {
        cout &amp;lt;&amp;lt; (*it) &amp;lt;&amp;lt; &quot; &quot;;
    }
    cout &amp;lt;&amp;lt; &quot;are in the hash set.&quot; &amp;lt;&amp;lt; endl;
    // 7. clear the hash set
    hashset.clear();
    // 8. check if the hash set is empty
    if (hashset.empty()) {
        cout &amp;lt;&amp;lt; &quot;hash set is empty now!&quot; &amp;lt;&amp;lt; endl;
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>C++ STL</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/11</guid>
      <comments>https://zeroone.tistory.com/11#entry11comment</comments>
      <pubDate>Thu, 21 Oct 2021 21:06:26 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] Divide and Conquer</title>
      <link>https://zeroone.tistory.com/10</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;분할정복 template&lt;/p&gt;
&lt;pre id=&quot;code_1634730163734&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Type divide_and_conquer( S ) {
    // (1). Divide the problem into a set of subproblems.
    [S1, S2, ... Sn] = divide(S)

    // (2). Solve the subproblem recursively,
    //   obtain the results of subproblems as [R1, R2... Rn].
    rets = [divide_and_conquer(Si) for Si in [S1, S2, ... Sn]]
    [R1, R2,... Rn] = rets

    // (3). combine the results from the subproblems.
    //   and return the combined result.
    return combine([R1, R2,... Rn])

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/10</guid>
      <comments>https://zeroone.tistory.com/10#entry10comment</comments>
      <pubDate>Wed, 20 Oct 2021 20:43:02 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Template] Backtracking</title>
      <link>https://zeroone.tistory.com/9</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Backtracking 전용 template&lt;/p&gt;
&lt;pre id=&quot;code_1634729956110&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Type backtrack(candidate) {

    if find_solution(candidate):
        output(candidate)
        return
    
    // iterate all possible candidates.
    for next_candidate in list_of_candidates:
        if is_valid(next_candidate):
            // try this partial candidate solution
            place(next_candidate)
            // given the candidate, explore further.
            backtrack(next_candidate)
            // backtrack
            remove(next_candidate)

}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/Template</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/9</guid>
      <comments>https://zeroone.tistory.com/9#entry9comment</comments>
      <pubDate>Wed, 20 Oct 2021 20:39:36 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][Leetcode] 208. Implement Trie (Prefix Tree)</title>
      <link>https://zeroone.tistory.com/8</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Trie를 c++로 구현해봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원문 :&amp;nbsp;&lt;a href=&quot;https://leetcode.com/problems/implement-trie-prefix-tree/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://leetcode.com/problems/implement-trie-prefix-tree/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;375&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zm1dx/btrh3oXgVfn/IdkurFsMNE3tOrXV2gkMkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zm1dx/btrh3oXgVfn/IdkurFsMNE3tOrXV2gkMkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zm1dx/btrh3oXgVfn/IdkurFsMNE3tOrXV2gkMkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzm1dx%2Fbtrh3oXgVfn%2FIdkurFsMNE3tOrXV2gkMkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;375&quot; height=&quot;352&quot; data-origin-width=&quot;375&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트라이(Trie) : 문자열을 저장하고 효율적으로 탐색하기 위한 트리 형태의 자료구조이다.&lt;/li&gt;
&lt;li&gt;자식으로 a-z까지 TreeNode들과 문자의 끝을 표시하는 end flag를 갖는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1634479320721&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class TrieNode {
private:
    bool endFlag;
    TrieNode* next[27 + 'a'];
public:
    TrieNode() {
        endFlag = false;
        memset(next, NULL, sizeof(next));
    }

    TrieNode* getNext(char c) {
        return next[c];
    }

    void setNext(char c) {
        next[c] = new TrieNode();
        // setEndFlag(false);
    }

    bool getEndFlag() {
        return endFlag;
    }

    void setEndFlag(bool endFlag) {
        this-&amp;gt;endFlag = endFlag;
    }
};

class Trie {
private:
    TrieNode* root;
public:
    Trie() {
        root = new TrieNode();
    }

    void insert(string word) {
        TrieNode* node = root;
        for (char c : word) {
            if (node-&amp;gt;getNext(c)) {
            }
            else {
                node-&amp;gt;setNext(c);
            }
            node = node-&amp;gt;getNext(c);
        }
        node-&amp;gt;setEndFlag(true);
    }

    bool search(string word) {
        TrieNode* node = root;
        for (char c : word) {
            if (node-&amp;gt;getNext(c)) {
                node = node-&amp;gt;getNext(c);
            }
            else {
                return false;
            }
        }
        return node-&amp;gt;getEndFlag();
    }

    bool startsWith(string prefix) {
        TrieNode* node = root;
        for (char c : prefix) {
            if (node-&amp;gt;getNext(c)) {
                node = node-&amp;gt;getNext(c);
            }
            else {
                return false;
            }
        }
        return true;       
    }
};

/**
 * Your Trie object will be instantiated and called as such:
 * Trie* obj = new Trie();
 * obj-&amp;gt;insert(word);
 * bool param_2 = obj-&amp;gt;search(word);
 * bool param_3 = obj-&amp;gt;startsWith(prefix);
 */&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘/오답노트</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/8</guid>
      <comments>https://zeroone.tistory.com/8#entry8comment</comments>
      <pubDate>Sun, 17 Oct 2021 23:22:06 +0900</pubDate>
    </item>
    <item>
      <title>[C++][STL] sort</title>
      <link>https://zeroone.tistory.com/7</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;LeetCode : &lt;span style=&quot;background-color: #f5f5f5; color: #000000;&quot;&gt;Sort an Array 문제를 풀다가 의문점이 생겼다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f5f5f5; color: #000000;&quot;&gt;제약조건은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;1 &amp;lt;= nums.length &amp;lt;= 5 * 10^4&lt;/li&gt;
&lt;li&gt;-5 * 104&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;= nums[i] &amp;lt;= 5 * 10^4&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f5f5f5; color: #000000;&quot;&gt;즉, nlog(n)으로 sorting해야하는 간단한 문제다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f5f5f5; color: #000000;&quot;&gt;근데 C++의 STL인 sort는 내부적으로 quick sort를 사용한다는데 어떻게 STL을 사용해 통과했을까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #f5f5f5;&quot;&gt;quick sort는 최악의 경우 &lt;b&gt;O(N^2)&lt;/b&gt;이다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #f5f5f5;&quot;&gt;당연히, merge sort 같은 &lt;b&gt;O(Nlog(N))&lt;/b&gt;을 사용해야할 줄 알았다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #f5f5f5;&quot;&gt;첫번째 풀이 merge sort다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1633316444485&quot; class=&quot;html xml&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public:
    void mergeSort(vector&amp;lt;int&amp;gt;&amp;amp; nums, int s, int e) {
        if (s != e) {
            int mid = (s+e)/2;
            mergeSort(nums, s, mid);
            mergeSort(nums, mid+1, e);
            merge(nums, s, mid, e);
        }
    }
    void merge(vector&amp;lt;int&amp;gt;&amp;amp; nums, int s, int m, int e) {
        int i = s;
        int j = m+1;
        int k = e;
        vector&amp;lt;int&amp;gt; tmp;
        while(i &amp;lt;= m &amp;amp;&amp;amp; j &amp;lt;= e) {
            if (nums[i] &amp;lt; nums[j]) {
                tmp.push_back(nums[i++]);
            }
            else {
                tmp.push_back(nums[j++]);
            }
        }

        while (i &amp;lt;= m) {
            tmp.push_back(nums[i++]);
        }
        while (j &amp;lt;= e) {
            tmp.push_back(nums[j++]);
        }

        for (int i = s; i &amp;lt;= e; i++) {
            nums[i] = tmp[i-s];
        }
    }

    vector&amp;lt;int&amp;gt; sortArray(vector&amp;lt;int&amp;gt;&amp;amp; nums) {
        mergeSort(nums, 0, nums.size()-1);
        return nums;
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runtime:&amp;nbsp;133&amp;nbsp;ms&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째 풀이, sort STL이다.&lt;/p&gt;
&lt;pre id=&quot;code_1633316523694&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
    public:
    vector&amp;lt;int&amp;gt; sortArray(vector&amp;lt;int&amp;gt;&amp;amp; nums) {
        sort(nums.begin(), nums.end());
        return nums;
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Runtime: 22 ms&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성공했다. 심지어 시간도 훨씬 빠르다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 케이스도 1~50000의 정렬된 vector를 넣어봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 되는 걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부적으로, sort는 단순히 quick sort가 아니라 최악의 경우를 대비한 로직이 있다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;따라서 문제풀때는 닥치고 sort쓰면 된다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>C++ STL</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/7</guid>
      <comments>https://zeroone.tistory.com/7#entry7comment</comments>
      <pubDate>Mon, 4 Oct 2021 12:04:49 +0900</pubDate>
    </item>
    <item>
      <title>[Algorithm][LeetCode] 1293. Shortest Path in a Grid with Obstacles Elimination</title>
      <link>https://zeroone.tistory.com/6</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;처음으로 leetcode hard 문제를 풀었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS와 Memoization을 적용한 풀이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초반엔 구조체 만들어서 풀었지만, tuple과 tie라는 STL을 적용하니 훨씬 깔끔해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 {}를 이용해 데이터를 묶어주면 tuple, vector형식으로 자동 변환해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간복잡도는 m * n * k, 즉 40*40*1600이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1632838524756&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
public:
    int shortestPath(vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&amp;amp; grid, int k) {
        vector&amp;lt;vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;&amp;gt; dp;       
        dp.assign(41, vector&amp;lt;vector&amp;lt;int&amp;gt;&amp;gt;(41, vector&amp;lt;int&amp;gt;(1601, 0)));
        
        int ms = grid.size(); 
        int ns = grid[0].size();
        int rb, cb, kb;
        int cnt = 0;
        
        queue&amp;lt;tuple&amp;lt;int, int, int&amp;gt; &amp;gt; q;
        q.push({0, 0, k});
        
        while (!q.empty()) {
            tie(rb, cb, kb) = q.front();
            q.pop();
            int nb = dp[rb][cb][kb];
            
            if (rb == ms-1 &amp;amp;&amp;amp; cb == ns-1) {
                continue;
            }
            if (rb &amp;lt; ms-1) {
                if (grid[rb+1][cb] == 1 &amp;amp;&amp;amp; kb &amp;gt; 0) {
                    if (!dp[rb+1][cb][kb-1]) {
                        dp[rb+1][cb][kb-1] = nb+1;                     
                        q.push({rb+1, cb, kb-1});
                    }
                }
                else if (grid[rb+1][cb] == 0) {
                    if (!dp[rb+1][cb][kb]) {
                        dp[rb+1][cb][kb] = nb+1;
                        q.push({rb+1, cb, kb});
                    }
                }
            }
            if (cb &amp;lt; ns-1) {
                if (grid[rb][cb+1] == 1 &amp;amp;&amp;amp; kb &amp;gt; 0) {
                    if (!dp[rb][cb+1][kb-1]) {
                        dp[rb][cb+1][kb-1] = nb+1;
                        q.push({rb, cb+1, kb-1});                        
                    }
                }
                else if (grid[rb][cb+1] == 0) {
                    if (!dp[rb][cb+1][kb]) {
                        dp[rb][cb+1][kb] = nb+1;
                        q.push({rb, cb+1, kb});                        
                    }
                }
            }
            if (rb &amp;gt; 0) {
                if (cb == 0)
                    continue;
                if (grid[rb-1][cb] == 1 &amp;amp;&amp;amp; kb &amp;gt; 0) {
                    if (!dp[rb-1][cb][kb-1]) {
                        dp[rb-1][cb][kb-1] = nb+1;
                        q.push({rb-1, cb, kb-1});                        
                    }
                }
                else if (grid[rb-1][cb] == 0) {
                    if (!dp[rb-1][cb][kb]) {
                        dp[rb-1][cb][kb] = nb+1;
                        q.push({rb-1, cb, kb});
                    }
                }
            }
            if (cb &amp;gt; 0) {
                if (rb == 0)
                    continue;
                if (grid[rb][cb-1] == 1 &amp;amp;&amp;amp; kb &amp;gt; 0) {
                    if (!dp[rb][cb-1][kb-1]) {
                        dp[rb][cb-1][kb-1] = nb+1;
                        q.push({rb, cb-1, kb-1});                        
                    }
                }
                else if (grid[rb][cb-1] == 0) {
                    if (!dp[rb][cb-1][kb]) {
                        dp[rb][cb-1][kb] = nb+1;
                        q.push({rb, cb-1, kb});                        
                    }
                }
            }
        }
        
        int mini = 1601;
        for (int i = 0; i &amp;lt; 1601; i++) {
            if (dp[ms-1][ns-1][i] != 0)
                mini = min(mini, dp[ms-1][ns-1][i]);
        }
        
        if (ms == 1 &amp;amp;&amp;amp; ns == 1)
            return 0;
        
        if (mini != 1601)
            return mini;
        else
            return -1;
    }
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘/오답노트</category>
      <author>zerone</author>
      <guid isPermaLink="true">https://zeroone.tistory.com/6</guid>
      <comments>https://zeroone.tistory.com/6#entry6comment</comments>
      <pubDate>Tue, 28 Sep 2021 23:20:00 +0900</pubDate>
    </item>
  </channel>
</rss>