<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>지식이 똥또로롱</title>
    <link>https://ymwoo1988.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 4 Apr 2026 13:28:55 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>앵꾸룩</managingEditor>
    <item>
      <title>JPA @OneToMany</title>
      <link>https://ymwoo1988.tistory.com/7</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;요청이 1개의 쿼리로 처리되길 기대했었는데 N개의 추가 쿼리가 발생 하는 현상&lt;/p&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;왜 N+1이 발생되는건가요?&lt;/li&gt;
&lt;li&gt;N+1 문제를 해결했지만, 왜 해결 됐는지 모르는 분&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;너무 많은 N+1 발생 케이스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@OneToOne&lt;/li&gt;
&lt;li&gt;@OneToMany&lt;/li&gt;
&lt;li&gt;@ManyToOne&lt;/li&gt;
&lt;li&gt;@ManyToMany&lt;/li&gt;
&lt;li&gt;단방향, 양방향&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 케이스들이 존재하는데 양이 많이 깨문에 이번 챕터에서는 @OneToMany내용을 다뤄보도록하겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지연(Lazy) 로딩 이란?&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;310&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFmmbs/btrQMtZwdUG/lTCg3KqXycG65mjdpAZUuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFmmbs/btrQMtZwdUG/lTCg3KqXycG65mjdpAZUuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFmmbs/btrQMtZwdUG/lTCg3KqXycG65mjdpAZUuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFmmbs%2FbtrQMtZwdUG%2FlTCg3KqXycG65mjdpAZUuK%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;1390&quot; height=&quot;310&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;310&quot;/&gt;&lt;/span&gt;&lt;/figure&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;여기서 @OneToMany로 fetch 전략을 지연(Lazy)로딩으로 선언하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 상황에서 findAll()해서 크루 목록을 조회해보면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nm9Hr/btrQPktbLa2/KSyH9PH6sqG5iTIL30VvL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nm9Hr/btrQPktbLa2/KSyH9PH6sqG5iTIL30VvL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nm9Hr/btrQPktbLa2/KSyH9PH6sqG5iTIL30VvL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnm9Hr%2FbtrQPktbLa2%2FKSyH9PH6sqG5iTIL30VvL0%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;1406&quot; height=&quot;452&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;452&quot;/&gt;&lt;/span&gt;&lt;/figure&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;위 조회 결과에서 할일목록은 Lazy로 설정하였기 때문에 Proxy 형태로만 들고 있는 상태 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;proxy의 대해서는 다른 챕터에서 상세하게 다루도록하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TODO &amp;gt; proxy 글 링크 걸기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;proxy영역에서는 크루의 목록을 for문을 돌려서 List&amp;lt;할일&amp;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;JPA에서는 1차 캐시 저장소에서 크루1의 할일을 찾고 없으면 실제 쿼리가 수행되고, 크루2의 할일도 찾고 없느면 실제쿼리가 수행되는 결과를 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Lazy 사용 시 객체 사용시점에 쿼리가 N번이 발생되게 됩니다 만약 수천개의 데이터목록이였다면 수천개의 쿼리가 발생된다고 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;1018&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GbfOr/btrQOPmE1Fj/ttUw24WGBgFFBJy1Gl5zk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GbfOr/btrQOPmE1Fj/ttUw24WGBgFFBJy1Gl5zk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GbfOr/btrQOPmE1Fj/ttUw24WGBgFFBJy1Gl5zk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGbfOr%2FbtrQOPmE1Fj%2FttUw24WGBgFFBJy1Gl5zk1%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;392&quot; height=&quot;605&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;1018&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결방법 : Fetch join&lt;/h3&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;(연관된 엔티티까지 영속성 컨텍스트에 전부 올려버버려요)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oiprG/btrQK2nt3TG/RIfDwUCxzp4TeJ0UhDuQuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oiprG/btrQK2nt3TG/RIfDwUCxzp4TeJ0UhDuQuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oiprG/btrQK2nt3TG/RIfDwUCxzp4TeJ0UhDuQuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoiprG%2FbtrQK2nt3TG%2FRIfDwUCxzp4TeJ0UhDuQuK%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;1416&quot; height=&quot;608&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;608&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;664&quot; data-origin-height=&quot;806&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGWyle/btrQPjnxPWg/iqdkx28ojiSshOO82wtMOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGWyle/btrQPjnxPWg/iqdkx28ojiSshOO82wtMOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGWyle/btrQPjnxPWg/iqdkx28ojiSshOO82wtMOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGWyle%2FbtrQPjnxPWg%2Fiqdkx28ojiSshOO82wtMOK%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;381&quot; height=&quot;806&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;806&quot;/&gt;&lt;/span&gt;&lt;/figure&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;DB를 거치지 않고, 데이터 꺼내서 반환!!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 1개의 쿼리로 문제 해결!&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;여기서 join과 fetch join을 알고 갈까요&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반 Join Fetch Join과 달리 연관 Entity에 Join을 걸어도 실제 쿼리에서 SELECT 하는 Entity는 오직 JPQL에서 조회하는 주체가 되는 Entity만 조회하여 영속화 조회의 주체가 되는 Entity만 SELECT 해서 영속화하기 때문에 데이터는 필요하지 않지만 연관 Entity가 검색조건에는 필요한 경우에 주로 사용됨
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제로 쿼리결과에 필요는 없으나 검색 시 필요한 테이블 항목이 있다면 join이 적합하게 사용될 수 있는 경우라고 생각합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Fetch Join 조회의 주체가 되는 Entity 이외에 Fetch Join이 걸린 연관 Entity도 함께 SELECT 하여 모두 영속화 Fetch Join이 걸린 Entity 모두 영속화하기 때문에 FetchType이 Lazy인 Entity를 참조하더라도 이미 영속성 컨텍스트에 들어있기 때문에 따로 쿼리가 실행되지 않은 채로 N+1문제가 해결됨&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;그러면 혹시 즉시(Eager)로딩도 있는데 이걸로는 해결 못하나요?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPQL에서 즉시 로딩 쿼리를 만들때는요&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;entity findAll 수행해줘!&lt;/li&gt;
&lt;li&gt;처음 쿼리를 만들 때 크루에 연관관계가 있는 엔티티는 신경 안쓰고 조회대상이 되는 Entity 기준으로만 쿼리를 만듬&lt;/li&gt;
&lt;li&gt;하지만 크루 목록 쿼리가 실행되고 나서 Eager조건으로 할일목록에 대한 즉시 N+1쿼리가 발생된다 (객체를 사용하지 않아도 수번의 쿼리가 즉시 실행 됨)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;1146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cv2aKe/btrQPgj3OlY/F1UjWrvSSf1Z6qUVM8Sbt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cv2aKe/btrQPgj3OlY/F1UjWrvSSf1Z6qUVM8Sbt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cv2aKe/btrQPgj3OlY/F1UjWrvSSf1Z6qUVM8Sbt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcv2aKe%2FbtrQPgj3OlY%2FF1UjWrvSSf1Z6qUVM8Sbt0%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;399&quot; height=&quot;676&quot; data-origin-width=&quot;676&quot; data-origin-height=&quot;1146&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;hellip;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;hellip;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론은 즉시로딩 최대한 사용하지말고, 지연 로딩 + fetch join 쓰세요!&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;하지만 fetch join은 무조건 답이 아니다!!&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 fetch join 문제상황&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 컬럼의 조건별 페이징을 하려고 했으나 join으로 인하여 조회대상컬럼의 값이 중복라인이 발생되는 경우 페이징 시 누락되는 현상이 나올 수 있음&lt;/li&gt;
&lt;li&gt;수달과 꼬재 기준으로 페이징을 걸고 싶었으나 join으로 인한 중복으로 꼬재의 아침 일찍 운동은 짤리는 현상이 나옴페이징 처리 시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBNzBj/btrQOlzDZ0f/mAk3omunoLq4OE3tEKogmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBNzBj/btrQOlzDZ0f/mAk3omunoLq4OE3tEKogmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBNzBj/btrQOlzDZ0f/mAk3omunoLq4OE3tEKogmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBNzBj%2FbtrQOlzDZ0f%2FmAk3omunoLq4OE3tEKogmK%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;563&quot; height=&quot;281&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;376&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;OneToMany 관계에서 페이징 처리할 때 해결법은?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ManyToOne&lt;/li&gt;
&lt;li&gt;@BatchSize()&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;&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;참고문헌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ni92wUkAmQI&amp;amp;feature=youtu.be&quot;&gt;https://www.youtube.com/watch?v=ni92wUkAmQI&amp;amp;feature=youtu.be&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://cobbybb.tistory.com/18&quot;&gt;https://cobbybb.tistory.com/18&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ict-nroo.tistory.com/132&quot;&gt;https://ict-nroo.tistory.com/132&lt;/a&gt;&lt;/p&gt;</description>
      <category>JPA</category>
      <category>jpa</category>
      <category>OneToMany</category>
      <author>앵꾸룩</author>
      <guid isPermaLink="true">https://ymwoo1988.tistory.com/7</guid>
      <comments>https://ymwoo1988.tistory.com/7#entry7comment</comments>
      <pubDate>Wed, 9 Nov 2022 20:14:52 +0900</pubDate>
    </item>
    <item>
      <title>웹소켓&amp;amp;스프링</title>
      <link>https://ymwoo1988.tistory.com/6</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;웹소켓? 언제사용하지?&lt;/li&gt;
&lt;li&gt;웹소켓 vs HTTP&lt;/li&gt;
&lt;li&gt;웹소켓을 지원하지 않은 환경에서는?&lt;/li&gt;
&lt;li&gt;STOMP and Spring-Messaging&lt;/li&gt;
&lt;li&gt;STOMP를 사용하는 장점&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;웹소켓? 언제사용하지?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹소켓은 실시간으로 반응을해야하는 곳에 필요 합니다. 예를들어 채팅이나, 바둑게임 같은 것을 예를들면 내가 글을 쓰거나 바둑한수를 두었을 때 상배방이 바로 확인 할 수 있어야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;1156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pI51K/btrPFB3FsJY/2JQjoLtrtk3NE3MKGCAtEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pI51K/btrPFB3FsJY/2JQjoLtrtk3NE3MKGCAtEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pI51K/btrPFB3FsJY/2JQjoLtrtk3NE3MKGCAtEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpI51K%2FbtrPFB3FsJY%2F2JQjoLtrtk3NE3MKGCAtEk%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;386&quot; height=&quot;578&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;1156&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;실시간성을 보장하는 서비스&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;h3 data-ke-size=&quot;size23&quot;&gt;웹소켓 vs HTTP&lt;/h3&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;Polling, Long Polling, Streaming&lt;/li&gt;
&lt;li&gt;HTTP 테스트 경기에서 공을 서로 주고 받고 하듯이 HTTP통신은 주고 받는 과정이 필요하다
&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;/li&gt;
&lt;li&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;/li&gt;
&lt;li&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;이런 경우 사용할 수 있는 것이 SockJS와 socket.io라이브러리 입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹소켓기능이 필요한 특정 서비스를 구현할 때에는 브라우저가 웹소켓을 지원하는지 확인해보고 우리가 서비스할 수 있는 브라우저를 정해서 서비스를 하던가, 그렇지 않은 경우 대안책으로 라이브러리를 통해서 기법들을 대신 사용할 수 있겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;STOMP and Spring-Messaging&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring boot에서 WebSocket의존성을 받아오면 Spring Messaging이라는 것이 같이 딸려서 옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Messaging이 뭐길래 딸려오나 싶어 의문이 생길 수도 있습니다. 이것을 알기전에 우선 STOMP라는 것을 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;STOMP&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Simple Text Oriented Messaging Protocol&lt;/li&gt;
&lt;li&gt;메시지 브로커를 활용하여 쉽게 메시지를 주고 받을 수 있는 프로토콜
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pus -Sub(발행 - 구독) : 발신자가 메시지를 발행하면 수신자가 그것을 수신하는 메시징 패러다음&lt;/li&gt;
&lt;li&gt;메시지 브로커 : 발신자의 메시지를 받아와서 수신자들에게 메시지를 전달하는 어떤 것&lt;/li&gt;
&lt;/ul&gt;
&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;1464&quot; data-origin-height=&quot;666&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PfRRV/btrPEEUdgWD/4JD3rtdALLkFBkatp9YDRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PfRRV/btrPEEUdgWD/4JD3rtdALLkFBkatp9YDRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PfRRV/btrPEEUdgWD/4JD3rtdALLkFBkatp9YDRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPfRRV%2FbtrPEEUdgWD%2F4JD3rtdALLkFBkatp9YDRk%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;1464&quot; height=&quot;666&quot; data-origin-width=&quot;1464&quot; data-origin-height=&quot;666&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽은 웹소켓구현 결과이고, 오른쪽은 STOMP구현결과 입니다. 웹소켓만 사용했을 때는 서버에서 보낸 메시지만 오가는 반면, STOMP를 사용하면 커맨드 헤더 바디의 형태로 메시지가 오가게 됩니다. 이렇게되면 프레임을 구축하거나 해석하는 어떠한 코드를 추가하지 않고 사용 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가로 왜 스프링부트위에서 STOMP를 사용해야하는걸까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 여러 사람들이 개발을 진행할 때 통신할 때 어떠한 양식을 사용할지 고민을 해야합니다 이런 경우를 대비하여 대체할 수 있는 것이 STOMP라고 할 수 있겠습니다.&lt;/p&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;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring이 STOMP를 사용하고 있을 때의 동작흐름을 한번 살펴볼게요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1438&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhFmDc/btrPEjWZbmy/xYHiH4torVtma7HrNcXfhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhFmDc/btrPEjWZbmy/xYHiH4torVtma7HrNcXfhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhFmDc/btrPEjWZbmy/xYHiH4torVtma7HrNcXfhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhFmDc%2FbtrPEjWZbmy%2FxYHiH4torVtma7HrNcXfhk%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;1438&quot; height=&quot;576&quot; data-origin-width=&quot;1438&quot; data-origin-height=&quot;576&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;왼쪽부분에 메시지를 보낼 발신자와, 메시지를 주신받을 구독자가 있습니다.&lt;/li&gt;
&lt;li&gt;발신자를 구독자들에게 메시지를 보내고 싶어하고 구독자들은 /topic를 구독하고 있다고 해볼게요&lt;/li&gt;
&lt;li&gt;이 상황에서 발신자는 바로 /topic을 destination 헤더로 넣어서 메시지를 송신할 수도 있겠지만, 서버 내에서의 어떤 처리 혹은 가공이 필요하다면 /app으로 메시지를 송신하게 됩니다.&lt;/li&gt;
&lt;li&gt;그리고 서버가 일을 모두 마쳤으면 가공되거나 처리된 메시지를 메시지 브로커에세 전달하게 되고 메시지브로거는 전달 받은 메시지들을 /topic을 구독하고 있는 구독자들에게 최종적으로 전달하게 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;STOMP를 사용하는 장점&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;외부 Messaging Queue를 사용할 수 있다&lt;/li&gt;
&lt;li&gt;Spring Security를 사용할 수 있다&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;감사합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/rvss-_t6gzg&quot;&gt;https://youtu.be/rvss-_t6gzg&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>웹소켓</category>
      <category>스프링</category>
      <category>웹소켓</category>
      <author>앵꾸룩</author>
      <guid isPermaLink="true">https://ymwoo1988.tistory.com/6</guid>
      <comments>https://ymwoo1988.tistory.com/6#entry6comment</comments>
      <pubDate>Wed, 26 Oct 2022 20:40:41 +0900</pubDate>
    </item>
    <item>
      <title>인증과 인가</title>
      <link>https://ymwoo1988.tistory.com/5</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;오늘의 주제&lt;/h3&gt;
&lt;ol 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;/ol&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인증 &amp;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;&amp;nbsp;사용자 이름과 비밀번호는&amp;nbsp;****가장 많이 사용되는&amp;nbsp;&lt;a href=&quot;https://www.okta.com/kr/products/adaptive-multi-factor-authentication/&quot;&gt;인증 요소&lt;/a&gt;입니다. 사용자가 데이터를 올바르게 입력하면 시스템은 아이덴티티가 유효하다고 판단하고 액세스를 허용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;https://www.okta.com/blog/2020/06/what-is-a-one-time-password-otp/&quot;&gt;일회용 핀&lt;/a&gt;.&lt;/b&gt;&amp;nbsp;단일 세션이나 트랜잭션에 한하여 액세스를 허용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인증 앱.&lt;/b&gt;&amp;nbsp;액세스를 허용하는 외부 기관을 통해 보안 코드를 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;a href=&quot;https://www.okta.com/blog/2020/07/biometric-authentication/&quot;&gt;생체인식&lt;/a&gt;.&lt;/b&gt;&amp;nbsp;사용자가 시스템에 액세스하기 위해 지문이나 망막 스캔을 제출합니다.&lt;/li&gt;
&lt;/ul&gt;
상황에 따라 인증 요소를 2가지 이상 성공적으로 확인해야만 시스템에 액세스할 수 있는 경우도 있습니다. 이러한 다중 요소 인증(MFA) 요건이 배포되어 비밀번호의 한계를 넘어 보안을 강화하는 경우도 많습니다.&lt;/li&gt;
&lt;li&gt;인증은 사용자의 신원을 검증하는 행위로서 보안 프로세스에서 첫 번째 단계입니다.&lt;/li&gt;
&lt;li&gt;인가 &amp;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;인증 (Authentication) 인가 (Authorization)&lt;/p&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;/td&gt;
&lt;td&gt;자격 증명 확인&lt;/td&gt;
&lt;td&gt;권한 허가/거부&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;진행 방식&lt;/td&gt;
&lt;td&gt;비밀번호, 생체인식, 일회용 핀 또는 앱&lt;/td&gt;
&lt;td&gt;보안 팀에서 관리하는 설정 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자가 볼 수 있는가?&lt;/td&gt;
&lt;td&gt;예&lt;/td&gt;
&lt;td&gt;아니오&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용자가 직접 변경할 수 있는가?&lt;/td&gt;
&lt;td&gt;부분적으로 가능&lt;/td&gt;
&lt;td&gt;불가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;데이터 전송&lt;/td&gt;
&lt;td&gt;ID 토큰 사용&lt;/td&gt;
&lt;td&gt;액세스 토큰 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Session / Cookie 방식&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Session/Cookie 방식 인증은 기본적으로 세션 저장소를 필요로 합니다. 세션 저장소는 로그인시 사용자 정보를 저장하고, 열쇠로 사용할 수 있는&amp;nbsp;세션 ID&amp;nbsp;를 만듭니다. 그리고 HTTP 헤더에 실어 클라이언트에게 보냅니다. 브라우저는 세션 ID 를 포함하는 쿠키를 저장하고있습니다. 인증이 필요한 요청에 해당 쿠키를 끼워 서버에 request 를 보냅니다.&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;/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;1422&quot; data-origin-height=&quot;792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDjwe3/btrOQxV338f/BfHjVu4al75EKfZuh5uVM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDjwe3/btrOQxV338f/BfHjVu4al75EKfZuh5uVM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDjwe3/btrOQxV338f/BfHjVu4al75EKfZuh5uVM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDjwe3%2FbtrOQxV338f%2FBfHjVu4al75EKfZuh5uVM0%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;1422&quot; height=&quot;792&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;792&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/li&gt;
&lt;li&gt;서버에서는 계정 정보를 읽어 사용자를 확인 후, 사용자의 고유 ID 값을 부여한 후 세션 저장소에 저장하고, 이와 연결되는&amp;nbsp;세션 ID&amp;nbsp;를 발행합니다.&lt;/li&gt;
&lt;li&gt;클라이언트는 서버에서 해당 세션 ID 를 받아 쿠키에 저장 한 후, 인증이 필요한 요청마다 쿠키를 헤더에 끼워 보냅니다.&lt;/li&gt;
&lt;li&gt;서버에서는 쿠키를 받아 세션 저장소에서 확인 한 후, 일치하는 정보를 가져옵니다.&lt;/li&gt;
&lt;li&gt;인증이 완료되고 서버는 사용자에 맞는 데이터를 보내줍니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Session 과 Cookie 의 차이점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Session
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에서 가지고있는&amp;nbsp;&lt;b&gt;정보&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cookie
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버에서 발급된 세션을 열기 위한&amp;nbsp;&lt;b&gt;키&lt;/b&gt;&amp;nbsp;값(세션 ID 라고 칭함)&lt;/li&gt;
&lt;li&gt;타입은 String이고, 공간 제약이 있어서 4KB 이상 저장이 불가능하다.&lt;/li&gt;
&lt;li&gt;쿠키는 Key=value 형태로 이루어져 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;Set-Cookie: &amp;lt;cookie-name&amp;gt;=&amp;lt;cookie-value&amp;gt;
&lt;/code&gt;&lt;/pre&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;쿠키만으로 인증을 할 경우, 해커가 HTTP 요청을 중간에서 뺏어갈 때,&amp;nbsp;&lt;b&gt;모든 정보가 탈취됩니다&lt;/b&gt;.또한 쿠키는 조작된 데이터일 수 있으므로 실제 정보가 존재하는 database 를 사용해서 작업합니다.따라서 보안과는 관련 없는 장바구니, 자동로그인 설정 같은 경우에 유용하게 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증의 책임을 서버가 지게 하기 위해서 세션을 함께 사용합니다.&amp;nbsp;&lt;b&gt;사용자는 쿠키를 이용하고, 서버에서는 쿠키를 받아 세션의 정보를 접근하는 방식으로 인증&lt;/b&gt;을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쿠키가 담긴 HTTP 요청이 도중에 노출되더라도 쿠키 자체(세션 ID) 는 유의미한 값을 갖고 있지 않습니다. 중요한 정보는 서버 세션에 존재합니다.&lt;/li&gt;
&lt;li&gt;고유의 ID 값을 발급받습니다.
&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;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해결책은 HTTPS 를 사용해 요청 자체를 탈취해도 안의 정보를 읽기 힘들게 하거나, 세션에 유효시간을 부여할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ol&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;JWT (JSON Web Token) 는 인증에 필요한 정보들을 암호화시킨 토큰을 의미합니다. 위의 세션/쿠키 방식과 유사하게 사용자는 Access Token (JWT Token) 을 HTTP 헤더에 실어 서버에 전송합니다. 토큰은&amp;nbsp;&lt;b&gt;임의로 생성된 비밀번호&lt;/b&gt; &amp;nbsp;같이 동작합니다. 제한된 수명을 가지고, 새로운 토큰은 한번 만료되면 새로 생성되어야합니다.(Refresh Token)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;토큰의 흐름
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자가 로그인을 합니다.&lt;/li&gt;
&lt;li&gt;서버에서는 계정 정보를 읽어 사용자를 확인 후, 사용자의 고유 ID 값을 부여한 후 기타 정보와 함께 Payload 에 집어넣습니다.&lt;/li&gt;
&lt;li&gt;JWT 토큰의 유효기간을 설정합니다.&lt;/li&gt;
&lt;li&gt;암호화할 Secret key 를 이용해 Access Token 을 발급합니다.&lt;/li&gt;
&lt;li&gt;사용자는 Access Token 을 받아 저장 후, 인증이 필요한 요청마다 토큰을 헤더에 실어 보냅니다.&lt;/li&gt;
&lt;li&gt;서버에서는 해당 토큰의 Verify Signature 를 Secret key 로 복호화한 후, 조작 여부, 유효기간을 확인합니다.&lt;/li&gt;
&lt;li&gt;검증이 완료되었을 경우, Payload 를 디코딩 하여 사용자의 ID 에 맞는 데이터를 가져옵니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;강제로 만료시킬 수 없다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세션/쿠키 인증 방식은 쿠키가 악의적으로 이용될 경우 쿠키를 삭제하면 됩니다. 미 발급된 JWT 에 대해서는 유효기간이 완료될 때 까지는 계속 사용이 가능합니다.&lt;br /&gt;그러나 JWT 는 유효기간이 지나기 전까지 정보들을 이용할 수 있습니다.&lt;br /&gt;이에 대한 해결책은, Access Token 유효기간을 짧게 하고 Refresh Token 이라는 새로운 토큰을 발급합니다. 그렇게 되면 Access Token 을 탈취당해도 상대적으로 피해를 줄일 수 있습니다.&lt;/li&gt;
&lt;/ul&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;Payload 정보가 제한적입니다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Payload 는 따로 암호화되지 않기 때문에 디코딩하면 누구나 정보를 확인할 수 있습니다. 따라서 유저의 중요한 정보들은 Payload 에 넣을 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JWT 의 길이
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JWT 의 길이는 길기 때문에 인증이 필요한 요청이 많아질수록 서버의 자원낭비가 발생합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;&lt;a href=&quot;https://www.okta.com/kr/identity-101/authentication-vs-authorization/&quot;&gt;https://www.okta.com/kr/identity-101/authentication-vs-authorization/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tofusand-dev.tistory.com/89#장단점&quot;&gt;https://tofusand-dev.tistory.com/89#장단점&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://d-dual.tistory.com/3&quot;&gt;https://d-dual.tistory.com/3&lt;/a&gt;&lt;/p&gt;</description>
      <category>보안</category>
      <category>세션</category>
      <category>인가</category>
      <category>인증</category>
      <category>쿠키</category>
      <category>토큰</category>
      <author>앵꾸룩</author>
      <guid isPermaLink="true">https://ymwoo1988.tistory.com/5</guid>
      <comments>https://ymwoo1988.tistory.com/5#entry5comment</comments>
      <pubDate>Wed, 19 Oct 2022 20:29:33 +0900</pubDate>
    </item>
    <item>
      <title>Spring AOP (AspectJ)</title>
      <link>https://ymwoo1988.tistory.com/4</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;인프라로직&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 메소드에 repository를 수행하는 시간을 체크하기위한 코딩이 되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 메소드가 수천개가 존재한다고 가정한다면, 전 영역에서 중복되는 코딩 작업이 발생될 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 단순히 repository만 수행하는 역활인데 시간을 체크하는 로직까지 껴있으니 코드 분석에 이해도가 떨어지는 형태가 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6Y7IM/btrOpTM06s3/KEiedGhOqkOuUqRrIN3dpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6Y7IM/btrOpTM06s3/KEiedGhOqkOuUqRrIN3dpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6Y7IM/btrOpTM06s3/KEiedGhOqkOuUqRrIN3dpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6Y7IM%2FbtrOpTM06s3%2FKEiedGhOqkOuUqRrIN3dpk%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;1422&quot; height=&quot;416&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;416&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;요점정리
&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;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;cores-cutting concern (횡단 관심사)
&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;동일한 횡단구간에서는 AOP의 관심사로 분리할 수 있는 구조를 생각 할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;요점저리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AOP를 참조함으로써 객체지향 프로그래밍 프로그램 구조에 대한 또 다른 사고방식을 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JAVA의 AOP 구현체&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;java는 AspectJ라는 구현체 존재&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AOP 용어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AOP용어중에는 여러가지가 있지만 중요한 4가지만 정리해보았습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Target
&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;/li&gt;
&lt;li&gt;Advice
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 부가 기능? Before, AfterRetuning, AfterThrowing, After, Around&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Join point
&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Point cut
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 advice가 적용 지점, Spring AOP에서는 advice가 적용될 메서드를 선정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AOP 구현&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AOP를 구현할 Class를 생성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메소드에 &lt;a href=&quot;https://www.notion.so/Around-0ef5b670e07f49449d17daff0fb88000&quot;&gt;@Around 어노테이션을 이용하여 특정 경로의 메소드 횡단에 공통작업을 적용 시킵니다.&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서!! 방안이 2가지가 있습니다.&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 class=&quot;aspectj&quot;&gt;&lt;code&gt;@Aspect
@Component
public class StopWatchAspectAdvice {
		// 경로를 선택하여 지정
		@Around(&quot;execution(* com.study.service.AuthServiceImpl.*(..))&quot;)
		public Object stopWatch(ProceedingJoinPoint joinPoint) throws Throwable {
				StopWatch stopWatch = new StopWatch();
				try {
						stoWatch.start();
						return joinPoint.proceed();
				} finally {
						stopWatch.stop();
						log.info(&quot;request spent {} ms&quot;, stopWatch.getLastTaaskTimeMillis());
				}
		}

		// 어노테이션 기반 지정
		@Around(&quot;@annotation(PerfomanceCheck)&quot;) // &amp;lt;&amp;lt; @PerfomanceCheck은 별도로 생성
		public Object stopWatch(ProceedingJoinPoint joinPoint) throws Throwable {
				StopWatch stopWatch = new StopWatch();
				try {
						stoWatch.start();
						return joinPoint.proceed();
				} finally {
						stopWatch.stop();
						log.info(&quot;request spent {} ms&quot;, stopWatch.getLastTaaskTimeMillis());
				}
		}
}
&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;AOP의 구현 방법&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;http://J.Java&quot;&gt;J.Java&lt;/a&gt; &amp;gt; J.class 컴파일하는 시점에 해당하는 AOP를 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;클래스 로드시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;J.class 클래스 로더가 메모리가 적제시킬때 AOP를 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프록시 패턴
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring AOP에서 사용하는것이며 부가기능을 제공하는 프록시로 감싸서 실행을 하는 방식&lt;/li&gt;
&lt;li&gt;IoC와 DI를 기반으로 하기 때문에 가능한 방식이라고 생각하면 좋겠습니다.&lt;img style=&quot;caret-color: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/brzJzx/btrOrdjnpBK/wxxOPJxSRLzwer3AhMj25K/img.png&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;472&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/li&gt;
&lt;li&gt;사진을 보시면 Controller에서 Service를 DI로 주입받을 때 Service클래스를 print한 상황입니다.&lt;/li&gt;
&lt;li&gt;그 다음에는 Service에 AOP를 적용하고 로그는 찍게되면 아래 이미지와 같이 $$뒤에 CGLIB라는 것이 관여를하고 있습니다&lt;img style=&quot;caret-color: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/bTMMHo/btrOqNFtpqV/fsg42gHFEw4dHo1idAKgf1/img.png&quot; data-origin-width=&quot;1306&quot; data-origin-height=&quot;420&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/li&gt;
&lt;li&gt;디버거를 찍어서 보게되면 target내부에 Service가 들어있습니다. 그 밖에는 CGLIB라는 프록시 개념이 감싸져있는 상태 입니다.&lt;/li&gt;
&lt;li&gt;여기서 프록시를 구현하는 방법이 2가지가 있는데 JDK dynimic proxy랑 CGLIB proxy가 있는데 궁금하니까 다른 챕에서 내용을 다뤄보도록 하겠습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Spring AOP vs AspectJ 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring AOP AspectJ&lt;/p&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;/td&gt;
&lt;td&gt;간단한 AOP 기능 제공&lt;/td&gt;
&lt;td&gt;완벽한 AOP 기능 제공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Join Point&lt;/td&gt;
&lt;td&gt;메서드 레벨만 지원&lt;/td&gt;
&lt;td&gt;생성자, 필드, 메서드 등 다양하게 지원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;weaving&lt;/td&gt;
&lt;td&gt;런타임 시에만 가능&lt;/td&gt;
&lt;td&gt;런타임은 제공하지 않음 compile-time, post-compile, load-time제공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;대상&lt;/td&gt;
&lt;td&gt;Spring Container가 관리하는 Bean에만 가능&lt;/td&gt;
&lt;td&gt;모든 Java Object에 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고자료&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본문 내용 : **&lt;b&gt;&lt;a href=&quot;https://youtu.be/Hm0w_9ngDpM&quot;&gt;https://youtu.be/Hm0w_9ngDpM&lt;/a&gt; (우아한Tech)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AspectJ : &lt;a href=&quot;https://www.eclipse.org/aspectj/doc/released/progguide/index.html&quot;&gt;https://www.eclipse.org/aspectj/doc/released/progguide/index.html&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring AOP : &lt;a href=&quot;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop&quot;&gt;https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop&lt;/a&gt;&lt;/p&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;private 메서드에 AOP어노테이션을 적용했을 때 AOP가 동작을 할 것인가?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동작을 안합니다. (동일선상) 같은 횡단의 자기자신을 호출하는 메소드가 선언되어있지 않으면 AOP는 동작하지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Filter, Intercepter가 AOP의 일종인가요?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AOP개념과 비슷하게 동작하기에 AOP라고 할 수 있을 것 같습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AOP 적용 된건지 알 수 있는게 있나요?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인텔리제이에 AOP적용 시 코드 박스 부분에 표기가 된다. (인텔리제이 짱)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AOP가 남용 될 때 문제점?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동일한 메소드에 여러개의 AOP가 적용 될 때 원치 않은 동작이 나올 수 있지 않을까 생각 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>AOP</category>
      <category>AOP</category>
      <category>AspectJ</category>
      <category>Spring AOP</category>
      <author>앵꾸룩</author>
      <guid isPermaLink="true">https://ymwoo1988.tistory.com/4</guid>
      <comments>https://ymwoo1988.tistory.com/4#entry4comment</comments>
      <pubDate>Wed, 12 Oct 2022 20:55:19 +0900</pubDate>
    </item>
    <item>
      <title>CI/CD와 무중단 배포</title>
      <link>https://ymwoo1988.tistory.com/3</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CI/CD&lt;/li&gt;
&lt;li&gt;무중단 배포&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;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;/li&gt;
&lt;li&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;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CI (Continuous Intergration)&lt;/h2&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;CI가 있기 전에..&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ICKjh/btrNXMtDscr/g4JnobAROEcq8l0kHABf41/img.png&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;496&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;CI가 있기 전에 개발자들은 일명 머지데이라는 날을 통해 모든 분기 소스코드를 병합해야 했습니다.또한 개발자들이 코드를 병합할 때 개발자의 실수로 에러가 발생하는 코드를 병합하는 과정이 반복이 된다면 맨 마지막 코드에서 에러가 발생했을 경우 어느부분에서 문제가 발생했는지 디버깅하기 굉장히 어려울 것입니다. 이는 굉장히 많은 수작업이 동반되었고 결과적으로 많은 리소스를 낭비하게 되었습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CI를 한다면
&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;/li&gt;
&lt;li&gt;CI 과정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;젠킨스와 같은 CI툴이 빌드와 테스트를 진행합니다.&lt;/li&gt;
&lt;li&gt;이때 이상이 없으면 코드를 병합합니다.&lt;/li&gt;
&lt;li&gt;하지만 문제가 발생할 경우 오류를 반환하여 문제를 확인할 수 있게 해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJpMuY/btrNXVDVZIM/gikxWrfK3gVtJZzyQMJVj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJpMuY/btrNXVDVZIM/gikxWrfK3gVtJZzyQMJVj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJpMuY/btrNXVDVZIM/gikxWrfK3gVtJZzyQMJVj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJpMuY%2FbtrNXVDVZIM%2FgikxWrfK3gVtJZzyQMJVj1%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;1328&quot; height=&quot;574&quot; data-origin-width=&quot;1328&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 4가지 규칙을 지켜야 진정한 CI라고 말합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마틴 파울러가 제시하는 CI의 4가지 규칙&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다은은 CD를 알아보려고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;424&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqkb7g/btrNYvklqKs/y4j6Bp3COWRQoXPNp6kWU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqkb7g/btrNYvklqKs/y4j6Bp3COWRQoXPNp6kWU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqkb7g/btrNYvklqKs/y4j6Bp3COWRQoXPNp6kWU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdqkb7g%2FbtrNYvklqKs%2Fy4j6Bp3COWRQoXPNp6kWU0%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;1398&quot; height=&quot;424&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;424&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 jar를 수동으로 배포하려고 하는데 수십대의 서버가 있다고 한다면 무수히 많은 배포과정을 반복적으로 처리해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런것들을 안전하고 자동화하여 빠르게 배포할 수 있는 기능이 존재합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CD (Continuous Deployment)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속적 배포라는 뜻으로 빌드의 결과물을 프로덕션으로 릴리스하는 작업을 자동화하는 것을 의미한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;지속적 제공과 지속적 배포&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1JVk1/btrNY1chCg5/T5Ij0HxU3NffR4xG3BOMK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1JVk1/btrNY1chCg5/T5Ij0HxU3NffR4xG3BOMK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1JVk1/btrNY1chCg5/T5Ij0HxU3NffR4xG3BOMK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1JVk1%2FbtrNY1chCg5%2FT5Ij0HxU3NffR4xG3BOMK1%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;1390&quot; height=&quot;238&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;238&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;지속적 통합&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;CD에서는 지속적제공과 지속적배포하는 말과 혼용되어 사용되고 있다는 것을 알게되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이둘을 구분하는 것이 굉장히 헤깔리실 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이둘의 차이는 마지막 프로덕션으로 릴리스하는 Deploy 작업의 자동화 여부 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드와 테스트까지의 자동화가 이루어졌을 때 이후 빌드의 결과물을 Staging환경에 자동으로 릴리즈하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속적 제공은 Staging 단게까지 프로덕션으로 릴리즈하는 작업을 의미하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지속적 배포는 Deploy 단꼐까지 자동화되는 것을 의미 합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CI/CD 흐름&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ygwM7/btrNX8C1UxP/k91mlkXYq5zwVHdunnvbz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ygwM7/btrNX8C1UxP/k91mlkXYq5zwVHdunnvbz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ygwM7/btrNX8C1UxP/k91mlkXYq5zwVHdunnvbz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FygwM7%2FbtrNX8C1UxP%2Fk91mlkXYq5zwVHdunnvbz0%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;1398&quot; height=&quot;506&quot; data-origin-width=&quot;1398&quot; data-origin-height=&quot;506&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;개발자가 코드의 병합을 요청하면&lt;/li&gt;
&lt;li&gt;CI/CD 툴이 빌드와 테스트를 진행 합니다.&lt;/li&gt;
&lt;li&gt;에러 발생 시 빠른 노티와 관련 오류 정보를 노출시켜 줍니다.&lt;/li&gt;
&lt;li&gt;병합이 정상적으로 이루어 졌을 때는 CD 작업이 진행되어 서버단까지 Deploy단계를 진행 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CI
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고객의 요구사항에 빠르게 대응하기 위해 나온 XP의 실천방안 중 1가지&lt;/li&gt;
&lt;li&gt;여러 명이 하나의 코드에 대해서 수정을 진행해도 지속적으로 통합하면서 관리할 수 있음을 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CD
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CI의 연장선에 있는 개념&lt;/li&gt;
&lt;li&gt;빌드의 결과물을 프로덕션으로 지속적으로 배포하는 것을 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무중단 배포&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;566&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dgKSTv/btrNZGyLRrF/07bTsqlyzAExXKFV7Fkbc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dgKSTv/btrNZGyLRrF/07bTsqlyzAExXKFV7Fkbc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dgKSTv/btrNZGyLRrF/07bTsqlyzAExXKFV7Fkbc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdgKSTv%2FbtrNZGyLRrF%2F07bTsqlyzAExXKFV7Fkbc0%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;1404&quot; height=&quot;566&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;566&quot;/&gt;&lt;/span&gt;&lt;/figure&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;배포할 때 기존서비스를 종료하고 새로운 서비스를 실행하는 과정에서 서비스 중단 문제가 발생됩니다 이를 해결하기위해 나온 개념이 무중단 배포 입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무중단 배포 구현 방법&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AWS에서 Blue-Green 무중단 배포&lt;/li&gt;
&lt;li&gt;도커를 이용한 무중단 배포&lt;/li&gt;
&lt;li&gt;L4, L7스위치를 이용한 무중단 배포&lt;/li&gt;
&lt;li&gt;Nginx를 이용한 무중단 배포&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;간단히 하자면 gateway 프로세스라고 볼 수 있음&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;1414&quot; data-origin-height=&quot;656&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oCTZm/btrNYeb7zRH/EbkuedWcgawgVLcNkyxMA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oCTZm/btrNYeb7zRH/EbkuedWcgawgVLcNkyxMA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oCTZm/btrNYeb7zRH/EbkuedWcgawgVLcNkyxMA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoCTZm%2FbtrNYeb7zRH%2FEbkuedWcgawgVLcNkyxMA0%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;1414&quot; height=&quot;656&quot; data-origin-width=&quot;1414&quot; data-origin-height=&quot;656&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cTSPqp/btrNXK3HDUx/iQms8nFoQVojQRsVOnfU0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cTSPqp/btrNXK3HDUx/iQms8nFoQVojQRsVOnfU0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cTSPqp/btrNXK3HDUx/iQms8nFoQVojQRsVOnfU0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcTSPqp%2FbtrNXK3HDUx%2FiQms8nFoQVojQRsVOnfU0k%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;1426&quot; height=&quot;640&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무중단 배포 방식&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Rolling 배포
&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;서버를 차례대로 업데이트 시키는 방식 1대씩 배포를 진행
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Canary 배포
&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;A/B 테스트로 활용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Blue / Green 배포
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Blue를 구버전, Green을 신버전으로 지칭&lt;/li&gt;
&lt;li&gt;구버전과 동일하게 신버전의 인스턴스를 구성&lt;/li&gt;
&lt;li&gt;신버전 배포 시 로드 벨런서를 통해 신버전으로만 트래픽을 전환&lt;/li&gt;
&lt;li&gt;사진
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/li&gt;
&lt;li&gt;단점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템 자원이 2배호 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&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;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;Rolling, Canary, Blue-Green&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&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;/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;참고문헌&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://youtu.be/sIPU_VkrguI&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://youtu.be/sIPU_VkrguI&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 style=&quot;list-style-type: none;&quot;&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>CICD</category>
      <category>CD/CD</category>
      <category>무중단배포</category>
      <author>앵꾸룩</author>
      <guid isPermaLink="true">https://ymwoo1988.tistory.com/3</guid>
      <comments>https://ymwoo1988.tistory.com/3#entry3comment</comments>
      <pubDate>Thu, 6 Oct 2022 20:57:13 +0900</pubDate>
    </item>
    <item>
      <title>Process &amp;amp; Tread</title>
      <link>https://ymwoo1988.tistory.com/2</link>
      <description>&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;프로그램 코드들이 load되면서 메모리에 올라가고 프로세스가 기동되는 기반이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;1190&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpI5Sb/btrMKUY6ttP/eN0qHRbMvxqN3ffZwIb3Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpI5Sb/btrMKUY6ttP/eN0qHRbMvxqN3ffZwIb3Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpI5Sb/btrMKUY6ttP/eN0qHRbMvxqN3ffZwIb3Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpI5Sb%2FbtrMKUY6ttP%2FeN0qHRbMvxqN3ffZwIb3Kk%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;1390&quot; height=&quot;1190&quot; data-origin-width=&quot;1390&quot; data-origin-height=&quot;1190&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;부모의 프로세스의 구성에서&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;IPC를 사용한 통신&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;/li&gt;
&lt;li&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;/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;크롬에서 여러탭을 실행한다 탭 하나가 오류가 나면 그 탭만 문제가 있고 다른 탭은 정상동작이 된다.&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;인터넷브라우저에서 하나의 탭에서 문제가 발생되면 브라우저 자체가 문제가 생긴다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Multi Core&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Concurrency 동시성 하나의 코어에서 하나 이상의 프로세스가 번갈아가면서 진행되지만 동시에 진행되는 것처럼 보이는 것&lt;/li&gt;
&lt;li&gt;Parallelism 병렬처리 둘 이상의 코어에서 동시에 하나 이상의 프로세스가 한꺼번에 진행되는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;/li&gt;
&lt;li&gt;스레드는 한 프로세스 내에서 나뉘어진 하나 이상의 실행 단위이다.&lt;/li&gt;
&lt;li&gt;한 어플리케이션에 대한 작업을 동시에 하기 위해서는 2가지 처리 방식(멀티 프로세스, 멀티스레디)가 있다.&lt;/li&gt;
&lt;li&gt;동시에 실행되는 것 처럼 보이기 위해서 실행단위는 시분할로cpu를 점유하며 context switching을 한다.&lt;/li&gt;
&lt;li&gt;멀티 프로세스는 독립적인 메모리를 가지고 있지만 멀티 스레드는 자원을 공유한다. 그것에 따른 각각의 장단점이 있다.&lt;/li&gt;
&lt;li&gt;멀티 코어는 하드웨어 측면에서 실행 단위를 병렬적으로 처리할 수 있도록 여러 프로세서가 있는 것이다.&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>쓰레드</category>
      <category>쓰레드</category>
      <category>프로세스</category>
      <author>앵꾸룩</author>
      <guid isPermaLink="true">https://ymwoo1988.tistory.com/2</guid>
      <comments>https://ymwoo1988.tistory.com/2#entry2comment</comments>
      <pubDate>Wed, 21 Sep 2022 20:15:28 +0900</pubDate>
    </item>
    <item>
      <title>전략패턴을 쉽게 이해해보자</title>
      <link>https://ymwoo1988.tistory.com/1</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;목차&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/li&gt;
&lt;li&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;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&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;메서드 호출과는 다르게 상속은 캡슐화를 깨트린다. 하위 클래스가 상위 클래스의 구현에 의존할 수 밖에 없기 때문이다. 상위 클래스의 구현은 변경될 수 있는데, 그러다보면 하위 클래스는 코드 수정 없이도 망가질 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;부모 클래스 동물 Animal을 만들었다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;public abstract class AnimalAbstract {
    abstract void move();
    abstract void speak();
}
&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;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 class=&quot;scala&quot;&gt;&lt;code&gt;public class LionAnimal extends AnimalAbstract {
    @Override
    void move() {
        System.out.println(&quot;네발로 걷는다&quot;);
    }

    @Override
    void speak() {
        System.out.println(&quot;어흥!&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;돼지&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class PigAnimal extends AnimalAbstract {
    @Override
    void move() {
        System.out.println(&quot;네발로 걷는다&quot;);
    }

    @Override
    void speak() {
        System.out.println(&quot;꿀꿀!&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;새&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;public class BirdAnimal extends AnimalAbstract {
    @Override
    void move() {
        System.out.println(&quot;날개를 펄억이며 하늘을 난다.&quot;);
    }

    @Override
    void speak() {
        System.out.println(&quot;짹짹!&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;여기서 문제점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;move에보면 사자와 돼지는 동일한 항목이 중첩되는 문제가 발생 된다.&lt;/li&gt;
&lt;li&gt;먹을 것 food를 추가하게되면 모든 하위클래스들에게 영향을 받는다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;AnimalAbstract에는 abstract void food(); 메소드가 추가될 것이고&lt;/li&gt;
&lt;li&gt;각 사자, 돼지, 새의 클래스에도 food()메소드를 &lt;a href=&quot;https://www.notion.so/Override-d6c57989705e4cdfa52d232e7d612d3a&quot;&gt;Override를 받아서 구현해줘야한다.&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이런 하위클래스가 수십개라면&amp;hellip; 엄청많은 코드를 수정해야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;컴포지션&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 문제를 모두 해결할 수 있는 방법이 있다. 상속하는 대신 새로운 클래스를 만들고, 기존 클래스 객체를 참조하는 private 필드를 하나 두는 것이다. 이러한 설계 방법을 컴포지션이라 한다.&amp;nbsp;&lt;b&gt;컴포지션&lt;/b&gt;을 사용하면 새로운 클래스는 기존 클래스의 내부 구현 방식의 영향에서 벗어나며, 기존 클래스에 새로운 메서드가 추가되더라도 전혀 영향을 받지 않게 된다.&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;&lt;b&gt;전달&lt;/b&gt;: 새 클래스의 인스턴스 메서드들은 기존 클래스의 대응하는 메서드를 호출해 그 결과를 반환&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;Animal이라는 구현체가 있고 move와 speak를 사용할 수 있는 기능이 있다고 하다
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;2가지의 기능이 폐쇄적이고 개방적으로 사용할 수 있어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Animal {

    private final Move move;
    private final Speak speak;

    public Animal(Move move, Speak speak) {
        this.move = move;
        this.speak = speak;
    }

    public void getMove() {
        move.move();
    }

    public void getSpeak() {
        speak.speak();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Move에 대한 기능
&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 class=&quot;java&quot;&gt;&lt;code&gt;public class FourLegsWalkMove implements Move {
    @Override
    public void move() {
        System.out.println(&quot;네발로 걷는다&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;날개로 날기&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class FlyMove implements Move {
    @Override
    public void move() {
        System.out.println(&quot;날개로 날기&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Speak에 대한 기능
&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 class=&quot;java&quot;&gt;&lt;code&gt;public class LionSpeak implements Speak {
    @Override
    public void speak() {
        System.out.println(&quot;어흥!&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;돼지 꿀꿀&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class PigSpeak implements Speak {
    @Override
    public void speak() {
        System.out.println(&quot;꿀꿀!&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;새 짹짹&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class BirdSpeak implements Speak {
    @Override
    public void speak() {
        System.out.println(&quot;짹짹!&quot;);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자 그럼 이제 Animal을 사용하여 다양한 동물을 만들어 봅시다&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public void test() {
    Animal lion = new Animal(new FourLegsWalkMove(), new LionSpeak());
    lion.getMove();
    lion.getSpeak();

    Animal pig = new Animal(new FourLegsWalkMove(), new PigSpeak());
    pig.getMove();
    pig.getSpeak();

    Animal bird = new Animal(new FlyMove(), new BirdSpeak());
    bird.getMove();
    bird.getSpeak();
}
&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;new Animal() 을 생성하는 시점에 역활을 조합해서 넣어줬다
&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;여기서 food가 추가된다면?
&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 class=&quot;java&quot;&gt;&lt;code&gt;public class ForkFood implements Food {
    @Override
    public void food() {
        System.out.println(&quot;돼지고기&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;사과&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class AppleFood implements Food {
    @Override
    public void food() {
        System.out.println(&quot;사과&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;이제 Animal에 적용하려면?
&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;3개의 인자를 받을 수 있는 새로운 생성자를 추가해두었다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Animal {

    private final Move move;
    private final Speak speak;
    private Food food;

    public Animal(Move move, Speak speak) {
        this.move = move;
        this.speak = speak;
    }

    public Animal(Move move, Speak speak, Food food) {
        this.move = move;
        this.speak = speak;
        this.food = food;
    }

    public void getMove() {
        move.move();
    }

    public void getSpeak() {
        speak.speak();
    }

    public Food getFood() {
        return food;
    }
}
&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;Animal 호출의 변경
&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;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public void test() {
    Animal lion = new Animal(new FourLegsWalkMove(), new LionSpeak(), new ForkFood());
    lion.getMove();
    lion.getSpeak();
    lion.getFood()

    Animal pig = new Animal(new FourLegsWalkMove(), new PigSpeak(), new AppleFood());
    pig.getMove();
    pig.getSpeak();
    pig.getFood();

    Animal bird = new Animal(new FlyMove(), new BirdSpeak());
    bird.getMove();
    bird.getSpeak();
}
&lt;/code&gt;&lt;/pre&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;그림으로도 이해를 도와드리겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2410&quot; data-origin-height=&quot;3070&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btWrk1/btrMG3X2WWB/AB4GcuSD7l1heSZM3NYal0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btWrk1/btrMG3X2WWB/AB4GcuSD7l1heSZM3NYal0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btWrk1/btrMG3X2WWB/AB4GcuSD7l1heSZM3NYal0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtWrk1%2FbtrMG3X2WWB%2FAB4GcuSD7l1heSZM3NYal0%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;2410&quot; height=&quot;3070&quot; data-origin-width=&quot;2410&quot; data-origin-height=&quot;3070&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>디자인패턴</category>
      <category>디자인패턴</category>
      <category>전략패턴</category>
      <author>앵꾸룩</author>
      <guid isPermaLink="true">https://ymwoo1988.tistory.com/1</guid>
      <comments>https://ymwoo1988.tistory.com/1#entry1comment</comments>
      <pubDate>Wed, 21 Sep 2022 20:12:45 +0900</pubDate>
    </item>
  </channel>
</rss>