<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>dongs</title>
    <link>https://dongs-record.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 08:26:06 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>hdk325</managingEditor>
    <item>
      <title>[OS] 프로세스 상태</title>
      <link>https://dongs-record.tistory.com/46</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로세스 상태 (Process State)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;os_process_states.png&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;223&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mVcb4/btr8keXbObb/of3bZPePaylDIqg5htvjO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mVcb4/btr8keXbObb/of3bZPePaylDIqg5htvjO1/img.png&quot; data-alt=&quot;http://faculty.cooper.edu/smyth/cs111/os/os1.htm&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mVcb4/btr8keXbObb/of3bZPePaylDIqg5htvjO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmVcb4%2Fbtr8keXbObb%2Fof3bZPePaylDIqg5htvjO1%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;570&quot; height=&quot;223&quot; data-filename=&quot;os_process_states.png&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;223&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://faculty.cooper.edu/smyth/cs111/os/os1.htm&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;new (생성 상태)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;프로세스를 생성 중인 상태. PCB를 할당받은 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;ready (준비 상태)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;자신의 차례를 기다리고 있는 상태.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;많은 프로세스들이 ready상태에서 자신의 차례를 기다린다. 이때 os는 실행 상태로 전환할 프로세스를 선택하는데 이 작업을 스케줄링이라 한다. CPU의 할당을 받으면 실행 상태가 되는데 준비 상태인 프로세스가 실행 상태로 전환되는 것을 &lt;b&gt;디스패치(Dispatch)&lt;/b&gt;라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;running (실행 상태)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;CPU의 할당을 받아서 실행하는 상태.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;waiting (대기 상태)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;입출력 작업이나 다른 이벤트가 발생하여 완료 인터럽트를 받을 때까지 기다리는 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;running -&amp;gt; ready&lt;br /&gt;- cpu를 할당받아 실행 중인 running 상태에서 할당받은 시간을 모두 사용하고 timer interrupt가 발생하면 ready 상태가 되어 다시 자신의 순서를 기다린다.&lt;br /&gt;&lt;br /&gt;running -&amp;gt; waiting&lt;br /&gt;- 실행 중인 프로세스가 입출력 작업을 기다리거나 다른 이벤트가 완료될 때까지 기다리는 경우 waiting 상태가 된다.&lt;br /&gt;&lt;br /&gt;waiting -&amp;gt; ready&lt;br /&gt;- 입출력 작업이 끝나서 완료 interrupt가 발생하면 ready 상태가 되어 자신의 순서를 기다린다.&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;terminated (종료 상태)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;프로세스가 종료된 상태. 프로세스가 사용한 PCB와 메모리를 정리한다.&lt;/p&gt;</description>
      <category>Computer Science/OS</category>
      <category>상태</category>
      <category>프로세스</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/46</guid>
      <comments>https://dongs-record.tistory.com/46#entry46comment</comments>
      <pubDate>Thu, 6 Apr 2023 11:45:26 +0900</pubDate>
    </item>
    <item>
      <title>[Querydsl] Querydsl 동적으로 정렬하는 방법</title>
      <link>https://dongs-record.tistory.com/45</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;게시글 조회 화면에서 검색타입, 정렬 방법에 따라 다른 결과를 반환해야 하는 기능을 구현하고 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMb94V/btr2ugM8bPo/v6cxA60MoetH2263szeKf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMb94V/btr2ugM8bPo/v6cxA60MoetH2263szeKf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMb94V/btr2ugM8bPo/v6cxA60MoetH2263szeKf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMb94V%2Fbtr2ugM8bPo%2Fv6cxA60MoetH2263szeKf1%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;701&quot; height=&quot;304&quot; data-filename=&quot;제목 없음.png&quot; data-origin-width=&quot;701&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;단순한 검색 기능이면 스프링 데이터 JPA로 JPQL을 사용했겠지만, 이번 기능은 고려해야 할 부분이 많았기 때문에 Querydsl을 사용해서 구현해 보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;where문 작성의 경우 BooleanExpression과 BooleanBuilder를 사용해서 간단하게 작성할 수 있었는데, 정렬 조건에 따른 작성을 어떻게 해야 하는지가 문제였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;처음엔 service단에서 sort값에 따라 처리하도록 아래와 같이 작성했었다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1678102362802&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//PostService
public Page&amp;lt;Post&amp;gt; findPosts(int page, int size, PostSearchDto postSearchDto, String sort) {
    PageRequest pageRequest = PageRequest.of(page, size);
    if (sort != null &amp;amp;&amp;amp; sort.equals(&quot;Likes&quot;)) {
        return postRepository.getPostsSortByLikes(postSearchDto, pageRequest);
    } else {
        return postRepository.getPostsSortByNewest(postSearchDto, pageRequest);
    }
}

//PostRepositoryImpl

//최신순
@Override
public Page&amp;lt;Post&amp;gt; getPostsSortByNewest(PostSearchDto postSearchDto, Pageable pageable) {

    List&amp;lt;Post&amp;gt; results = queryFactory
            .select(post)
            .from(post)
            .leftJoin(post.pet, pet)
            .where(codeEq(postSearchDto.getCode()), typeEq(postSearchDto))
            .orderBy(post.id.desc())
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .fetch();
	//...
}

//좋아요 순
@Override
public Page&amp;lt;Post&amp;gt; getPostsSortByLikes(PostSearchDto postSearchDto, Pageable pageable) {
    List&amp;lt;Post&amp;gt; results = queryFactory
            .select(post)
            .from(post)
            .leftJoin(post.pet, pet)
            .where(codeEq(postSearchDto.getCode()), typeEq(postSearchDto))
            .orderBy(post.likesCnt.desc())
            .orderBy(post.id.desc())
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .fetch();
    //...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;댓글 순까지 작성하면 orderBy를 제외한 다른 절들은 똑같은데 orderBy 때문에 3개의 메서드가 작성되는 게 별로였고 추후에 조건이 추가된다면 또 메서드를 만들어야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;OrderSpecifier&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Querydsl은 동적으로 정렬조건을 적용할 수 있게 OrderSpecifier를 제공한다.&lt;/p&gt;
&lt;pre id=&quot;code_1678103435479&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Override
public Page&amp;lt;Post&amp;gt; getPosts(PostSearchDto postSearchDto, Pageable pageable, String sort) {
    List&amp;lt;Post&amp;gt; results = queryFactory
            .select(post)
            .from(post)
            .leftJoin(post.pet, pet).fetchJoin()
            .leftJoin(post.postComments, postComment)
            .where(codeEq(postSearchDto.getCode()), typeEq(postSearchDto))
            .orderBy(getOrderSpecifier(sort).stream().toArray(OrderSpecifier[]::new))
            .groupBy(post.id)
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .fetch();
    
    //...
}

private List&amp;lt;OrderSpecifier&amp;gt; getOrderSpecifier(String sort) {
    List&amp;lt;OrderSpecifier&amp;gt; orders = new ArrayList&amp;lt;&amp;gt;();
    if (StringUtils.hasText(sort)) {
        Order direction = Order.DESC;
        switch (sort) {
            case &quot;likes&quot;:
                orders.add(new OrderSpecifier(direction, post.likesCnt));
                orders.add(new OrderSpecifier(direction, post.id));
                break;
            case &quot;comments&quot;:
                orders.add(new OrderSpecifier(direction, postComment.id.count()));
                orders.add(new OrderSpecifier(direction, post.id));
                break;
            case &quot;newest&quot;:
                orders.add(new OrderSpecifier(direction, post.id));
                break;
            default:
                throw new BusinessLogicException(ExceptionCode.INVALID_SORT_TYPE);
        }
    }
    return orders;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;위와 같이 List에 정렬 조건별로 OrderSpecifier를 추가해서 반환하는 메서드를 만들어 사용하면 정렬 조건이 추후에 조건이 바뀌거나 추가되어도 쉽게 적용이 가능하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;참고 블로그&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a title=&quot;참고 블로그&quot; href=&quot;https://dingdingmin-back-end-developer.tistory.com/entry/Springboot-JPA-Querydsl-%EB%8F%99%EC%A0%81-%EC%A0%95%EB%A0%AC-OrderSpecifier&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dingdingmin-back-end-developer.tistory.com/entry/Springboot-JPA-Querydsl-%EB%8F%99%EC%A0%81-%EC%A0%95%EB%A0%AC-OrderSpecifier&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1678104595873&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Springboot JPA Querydsl 동적 정렬 OrderSpecifier&quot; data-og-description=&quot;SQL 동적 정렬이란? 하나의 API에서 정렬 조건을 동적으로 변경해, 정렬 혹은 정렬 + 페이징을 진행하는 것을 의미합니다. 예시를 보며, 필요한 상황이 언제이며, 어떻게 해결하는지 알아가 보겠습&quot; data-og-host=&quot;dingdingmin-back-end-developer.tistory.com&quot; data-og-source-url=&quot;https://dingdingmin-back-end-developer.tistory.com/entry/Springboot-JPA-Querydsl-%EB%8F%99%EC%A0%81-%EC%A0%95%EB%A0%AC-OrderSpecifier&quot; data-og-url=&quot;https://dingdingmin-back-end-developer.tistory.com/entry/Springboot-JPA-Querydsl-%EB%8F%99%EC%A0%81-%EC%A0%95%EB%A0%AC-OrderSpecifier&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bSsmGu/hyRREQjzsW/siprvewZmN5bwXgPcwsEO1/img.png?width=800&amp;amp;height=610&amp;amp;face=0_0_800_610,https://scrap.kakaocdn.net/dn/eqlEs7/hyRREJx2zJ/QIYsKVfndl0jJMt0VFRxjK/img.png?width=800&amp;amp;height=610&amp;amp;face=0_0_800_610,https://scrap.kakaocdn.net/dn/bxwRFk/hyRQlY67d7/l2xWRBNvZKRd7iMkJuZDs1/img.png?width=890&amp;amp;height=937&amp;amp;face=0_0_890_937&quot;&gt;&lt;a href=&quot;https://dingdingmin-back-end-developer.tistory.com/entry/Springboot-JPA-Querydsl-%EB%8F%99%EC%A0%81-%EC%A0%95%EB%A0%AC-OrderSpecifier&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://dingdingmin-back-end-developer.tistory.com/entry/Springboot-JPA-Querydsl-%EB%8F%99%EC%A0%81-%EC%A0%95%EB%A0%AC-OrderSpecifier&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bSsmGu/hyRREQjzsW/siprvewZmN5bwXgPcwsEO1/img.png?width=800&amp;amp;height=610&amp;amp;face=0_0_800_610,https://scrap.kakaocdn.net/dn/eqlEs7/hyRREJx2zJ/QIYsKVfndl0jJMt0VFRxjK/img.png?width=800&amp;amp;height=610&amp;amp;face=0_0_800_610,https://scrap.kakaocdn.net/dn/bxwRFk/hyRQlY67d7/l2xWRBNvZKRd7iMkJuZDs1/img.png?width=890&amp;amp;height=937&amp;amp;face=0_0_890_937');&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;Springboot JPA Querydsl 동적 정렬 OrderSpecifier&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;SQL 동적 정렬이란? 하나의 API에서 정렬 조건을 동적으로 변경해, 정렬 혹은 정렬 + 페이징을 진행하는 것을 의미합니다. 예시를 보며, 필요한 상황이 언제이며, 어떻게 해결하는지 알아가 보겠습&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;dingdingmin-back-end-developer.tistory.com&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;</description>
      <category>Programming/Spring</category>
      <category>OrderSpecifier</category>
      <category>querydsl</category>
      <category>동적 정렬</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/45</guid>
      <comments>https://dongs-record.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 6 Mar 2023 21:04:47 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] HttpServletRequest 요청마다 같은 주소값을 반환하는 이유</title>
      <link>https://dongs-record.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;부트캠프가 끝나고 예전에 수강했던 김영한님의 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술을 다시 듣고 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;서블릿 부분을 보던 중 의아한 부분이 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&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;스크린샷 2023-02-25 오후 4.17.31.png&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;1002&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsmxb2/btr0JNF9nhB/JNKjKUmaK0wi26nhUkTTr0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsmxb2/btr0JNF9nhB/JNKjKUmaK0wi26nhUkTTr0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsmxb2/btr0JNF9nhB/JNKjKUmaK0wi26nhUkTTr0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbsmxb2%2Fbtr0JNF9nhB%2FJNKjKUmaK0wi26nhUkTTr0%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;739&quot; height=&quot;438&quot; data-filename=&quot;스크린샷 2023-02-25 오후 4.17.31.png&quot; data-origin-width=&quot;1690&quot; data-origin-height=&quot;1002&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;스프링의 내장 톰캣 서버는 서블릿들을 스캔하여 서블릿 컨테이너에 싱글톤으로 관리하면서 요청마다 WAS는 &lt;b&gt;Request, Response 객체를 새로 만들어서&lt;/b&gt; 서블릿 객체를 호출한다. 즉, 요청마다 request와 response객체는 요청마다 다른 객체가 만들어져서 servlet을 호출한다고 이해했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&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;스크린샷 2023-02-25 오후 4.28.40.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dvLah3/btr0BAInkoh/BuKmh4iuV0BRXl6xbSkkVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dvLah3/btr0BAInkoh/BuKmh4iuV0BRXl6xbSkkVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dvLah3/btr0BAInkoh/BuKmh4iuV0BRXl6xbSkkVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdvLah3%2Fbtr0BAInkoh%2FBuKmh4iuV0BRXl6xbSkkVK%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;2002&quot; height=&quot;860&quot; data-filename=&quot;스크린샷 2023-02-25 오후 4.28.40.png&quot; data-origin-width=&quot;2002&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-25 오후 4.29.20.png&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buE0lh/btr0BEjHKT7/4fscMeDfuP5WSGXIj1O74K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buE0lh/btr0BEjHKT7/4fscMeDfuP5WSGXIj1O74K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buE0lh/btr0BEjHKT7/4fscMeDfuP5WSGXIj1O74K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuE0lh%2Fbtr0BEjHKT7%2F4fscMeDfuP5WSGXIj1O74K%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;1030&quot; height=&quot;260&quot; data-filename=&quot;스크린샷 2023-02-25 오후 4.29.20.png&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;위와 같이 코드를 작성하고 요청 결과를 확인하다가 request, response가 같은 객체를 사용하고 있는 것을 확인했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;강의에서는 요청마다 request, response를 생성해서 servlet을 호출한다고 했는데 같은 객체를 사용하길래 궁금해서 찾아본 결과 나와 같이 궁금했던 사람이 질문한 글을 발견했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/questions/307198/http-%EC%9A%94%EC%B2%AD%EC%9D%84-%EB%B3%B4%EB%82%BC%EB%95%8C%EB%A7%88%EB%8B%A4-request-response-%EA%B0%9D%EC%B2%B4%EC%9D%98-%EC%A3%BC%EC%86%8C%EA%B0%92%EC%9D%B4-%EB%B3%80%ED%95%98%EC%A7%80-%EC%95%8A%EB%8A%94-%EC%9D%B4%EC%9C%A0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.inflearn.com/questions/307198/http-%EC%9A%94%EC%B2%AD%EC%9D%84-%EB%B3%B4%EB%82%BC%EB%95%8C%EB%A7%88%EB%8B%A4-request-response-%EA%B0%9D%EC%B2%B4%EC%9D%98-%EC%A3%BC%EC%86%8C%EA%B0%92%EC%9D%B4-%EB%B3%80%ED%95%98%EC%A7%80-%EC%95%8A%EB%8A%94-%EC%9D%B4%EC%9C%A0&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;정리하면 톰캣의 RequestFacade객체는 최적화를 위해 객체를 계속 생성하지 않고 요청이 끝나면 Facade객체를 초기화하고 다른 요청이 오면 재사용한다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;sleep을 적용하고 요청을 반복하면 사용되는 객체가 다른 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&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;스크린샷 2023-02-25 오후 4.39.07.png&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;264&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blJw4q/btr0IGUQct2/fq67ZyHtnk9dGtSrx7VTL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blJw4q/btr0IGUQct2/fq67ZyHtnk9dGtSrx7VTL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blJw4q/btr0IGUQct2/fq67ZyHtnk9dGtSrx7VTL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblJw4q%2Fbtr0IGUQct2%2Ffq67ZyHtnk9dGtSrx7VTL0%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;1044&quot; height=&quot;264&quot; data-filename=&quot;스크린샷 2023-02-25 오후 4.39.07.png&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;264&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Programming/Spring</category>
      <category>HttpServletRequest</category>
      <category>HttpServletResponse</category>
      <category>서블릿</category>
      <category>톰캣</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/44</guid>
      <comments>https://dongs-record.tistory.com/44#entry44comment</comments>
      <pubDate>Sat, 25 Feb 2023 16:48:08 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] RequestContextHolder를 통해 HttpServletRequest, Response 가져오기</title>
      <link>https://dongs-record.tistory.com/43</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;스프링 HttpServletRequest, HttpServletResponse는 RequestContextHolder를 통해 가져오기&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;ServletRequestAttributes servletContainer = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

HttpServletResponse response = servletContainer.getResponse();
HttpServletRequest request = servletContainer.getRequest();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Spring</category>
      <category>HttpServletRequest</category>
      <category>HttpServletResponse</category>
      <category>RequestContextHolder</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/43</guid>
      <comments>https://dongs-record.tistory.com/43#entry43comment</comments>
      <pubDate>Fri, 17 Feb 2023 15:48:50 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 같은 타입의 빈 문제 해결 방법(@Primary, @Qualifier)</title>
      <link>https://dongs-record.tistory.com/42</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;스프링은 빈과 연관된 의존관계를 주입할 때 스프링 컨테이너에서 해당 빈을 조회해서 의존관계를 주입한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;만약, 같은 타입의 빈이 두 개 이상 존재하면 스프링은 의존관계를 주입할 때 어떤 빈을 주입해야 할지 모르기 때문에 애플리케이션은 실행되지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Animal 인터페이스와 이를 구현한 Cat, Dog 클래스가 있고 AnimalService에서 Animal을 주입받는다고 가정하면 콘솔에 다음과 같이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Animal&lt;/h4&gt;
&lt;pre id=&quot;code_1676464103302&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.animal;

public interface Animal {}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Cat&lt;/h4&gt;
&lt;pre id=&quot;code_1676464128595&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.animal;

import org.springframework.stereotype.Component;

@Component
public class Cat implements Animal{
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Dog&lt;/h4&gt;
&lt;pre id=&quot;code_1676464137020&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.animal;


import org.springframework.stereotype.Component;

@Component
public class Dog implements Animal{
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AnimalService&lt;/h3&gt;
&lt;pre id=&quot;code_1676464322016&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package hello.core.animal;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class AnimalService {
    
    private final Animal animal;
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1676464566506&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of constructor in hello.core.animal.AnimalService required a single bean, but 2 were found:
	- cat: defined in file [~\Cat.class]
	- dog: defined in file [~\Dog.class]


Action:

Consider marking one of the beans as @Primary, 
updating the consumer to accept multiple beans,or 
using @Qualifier to identify the bean that should be consumed


Process finished with exit code 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;위와 같이 3가지 방법을 사용하라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. @Primary&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;@Primary는 우선순위를 지정하는 어노테이션이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;의존관계 주입 시 여러 개의 빈이 매칭되면 @Primay를 적용한 빈이 우선권을 갖게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1676464749102&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Primary
@Component
public class Dog implements Animal{
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. @Qualifier&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;@Qualifier는 추가 구분자를 붙여주는 방법이다. 별명처럼 추가적인 방법을 제공하는 것일 뿐 빈 이름을 변경하는 것이 아니다.&lt;/p&gt;
&lt;pre id=&quot;code_1676465221038&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
//@RequiredArgsConstructor
//롬복 사용시 @Qualifier를 사용하기 위해선 추가적인 설정이 필요하기 때문에 주석 처리
public class AnimalService {

    private final Animal animal;

    public AnimalService(@Qualifier(&quot;dogdog&quot;) Animal animal) {
        this.animal = animal;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 여러 개의 빈을 한 번에 받기(updating the consumer to accept multiple beans)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;의도적으로 여러 개의 빈이 필요할 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;스프링에서는 Collection 주입을 지원해 주기 때문에&amp;nbsp;같은 타입의 여러 빈이 존재하거나 필드나 파라미터 변수의 타입이 Collection, List, Map 일 경우 컬렉션으로 넘겨주어 한 번에 의존 관계를 맺게 해 준다.&lt;/p&gt;
&lt;pre id=&quot;code_1676465635438&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@Service
@RequiredArgsConstructor
public class AnimalService {

    private final Map&amp;lt;String,Animal&amp;gt; animal;

    @PostConstruct
    public void init() {
        log.info(&quot;animal = {}&quot;, animal);
    }
}

//animal = {cat=hello.core.animal.Cat@29138d3a, dog=hello.core.animal.Dog@5cbe2654}&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;nbsp; : 김영한님 스프링 핵심 원리 - 기본편&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard&quot;&gt;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming/Spring</category>
      <category>@primary</category>
      <category>@Qualifier</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/42</guid>
      <comments>https://dongs-record.tistory.com/42#entry42comment</comments>
      <pubDate>Wed, 15 Feb 2023 21:57:16 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 스프링 컨테이너와 빈</title>
      <link>https://dongs-record.tistory.com/30</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;스프링 컨테이너 (Spring Container)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;스프링 컨테이너는 애플리케이션 내부에서 사용되는 객체들을 관리한다.&amp;nbsp;&lt;br /&gt;정확히는 애플리케이션 빈의 생명주기를 관리하는데 빈 생성, 관리, 제거 등의 역할을 담당하는 곳이다. 객체들의 의존성 또한 관리해주기 때문에 개발자는 모듈 간 의존 및 결합으로 인해 발생하는 문제로부터 자유로워지고 핵심 로직에 집중할 수 있게 된다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;컨테이너는 BeanFactory와 BeanFacotry를 상속받아 사용하는 ApplicationContext가 있다.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;ApplicationContext가 BeanFactory의 기능에 더해 부가적으로 국제화, 환경변수 등 여러 기능을 제공하기 때문에 대부분의 경우에는 ApplicationContext를 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ApplicationContext.PNG&quot; data-origin-width=&quot;957&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kTqJp/btrO30XLEsU/bg89DBRQdAeMbz4u5tkDS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kTqJp/btrO30XLEsU/bg89DBRQdAeMbz4u5tkDS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kTqJp/btrO30XLEsU/bg89DBRQdAeMbz4u5tkDS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkTqJp%2FbtrO30XLEsU%2Fbg89DBRQdAeMbz4u5tkDS0%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;957&quot; height=&quot;332&quot; data-filename=&quot;ApplicationContext.PNG&quot; data-origin-width=&quot;957&quot; data-origin-height=&quot;332&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1666179440313&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
		MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
        
        }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;스프링 컨테이너를 사용할 땐 AnnotationConext 인터페이스를 구현한 AnnotationConfigApplicationConext를 사용하고 파라미터로 @Configuration 애너테이션이 붙은 구성 정보 클래스를 넣어준다&lt;/p&gt;
&lt;pre id=&quot;code_1666179972786&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 MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(),discountPolicy());
    }
    @Bean
    public DiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }
}


ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);&lt;/code&gt;&lt;/pre&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;1. 스프링 컨테이너 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;new AnnotationConfigApplicationConext(AppConfig.class)처럼 파라미터로 구성 정보 클래스를 넣어준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&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;size14&quot;&gt;컨테이너는 파라미터로 넘어온 클래스들을 실행시켜 빈들을 컨테이너에 등록한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;이때 빈 이름은 @Bean 애너테이션이 붙은 메서드의 이름으로 저장된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;컨테이너1.PNG&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhVEQv/btrYY8e96c7/cnjggBSJuJwf4vnFbZkVj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhVEQv/btrYY8e96c7/cnjggBSJuJwf4vnFbZkVj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhVEQv/btrYY8e96c7/cnjggBSJuJwf4vnFbZkVj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhVEQv%2FbtrYY8e96c7%2FcnjggBSJuJwf4vnFbZkVj1%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;1088&quot; height=&quot;368&quot; data-filename=&quot;컨테이너1.PNG&quot; data-origin-width=&quot;1088&quot; data-origin-height=&quot;368&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 data-ke-size=&quot;size14&quot;&gt;컨테이너는 설정 정보를 참고해서 의존관계 주입을 수행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스프링 빈 (Spring Bean)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;빈은 스프링 컨테이너에 의해 관리되는 재사용 소프트웨어 컴포넌트이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;즉, @Bean 애너테이션이 적힌 메서드를 모두 호출해서 스프링 컨테이너에 저장되는 객체들을 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;빈 관련 메서드&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;1. ac.getBeanDefinitionNames() : 컨테이너에 등록된 모든 빈 이름 조회&lt;br /&gt;2. ac.getBean() : 빈 이름으로 빈 객체 조회 (빈 이름, 타입), (타입)&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; &amp;nbsp; &amp;nbsp; &amp;nbsp;-&amp;gt; 조회할 빈이 없으면 예외가 발생한다. (NoSuchBeanDefinitionException)&lt;br /&gt;3. ac.getRole() : 스프링 내부에서 사용하는 빈과 자체적으로 등록한 빈 구별할 수 있는 메서드&lt;br /&gt;3 - 1. BeanDefinition.ROLE_APPLICATION : 개발자가 정의한 빈&lt;br /&gt;3 - 2. BeanDefinition.ROLE_INFRASTRUCTURE : 스프링 내부적으로 사용하는 빈&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;참고 자료&amp;nbsp; : 김영한님 스프링 핵심 원리 - 기본편&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard&quot;&gt;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8/dashboard&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming/Spring</category>
      <category>빈</category>
      <category>스프링</category>
      <category>스프링 컨테이너</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/30</guid>
      <comments>https://dongs-record.tistory.com/30#entry30comment</comments>
      <pubDate>Mon, 13 Feb 2023 14:44:28 +0900</pubDate>
    </item>
    <item>
      <title>SEB_BE - Main Project 회고</title>
      <link>https://dongs-record.tistory.com/41</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;pawpaw.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkBTR3/btrX3ZKh8eV/0jNkKmXKxIYJ0kgQknz1F0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkBTR3/btrX3ZKh8eV/0jNkKmXKxIYJ0kgQknz1F0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkBTR3/btrX3ZKh8eV/0jNkKmXKxIYJ0kgQknz1F0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkBTR3%2FbtrX3ZKh8eV%2F0jNkKmXKxIYJ0kgQknz1F0%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;265&quot; height=&quot;265&quot; data-filename=&quot;pawpaw.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;약 4주(23/01/03 ~ 23/02/03) 간의 메인 프로젝트가 끝났다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&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;image_9787287701509971855291.jpg&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl2Rbm/btrX9EZie3r/TWK5a7xogP9bGmD03BB9H1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl2Rbm/btrX9EZie3r/TWK5a7xogP9bGmD03BB9H1/img.jpg&quot; data-alt=&quot;http://blog.naver.com/rhkdtls8092/220260842686&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl2Rbm/btrX9EZie3r/TWK5a7xogP9bGmD03BB9H1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl2Rbm%2FbtrX9EZie3r%2FTWK5a7xogP9bGmD03BB9H1%2Fimg.jpg&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;412&quot; data-filename=&quot;image_9787287701509971855291.jpg&quot; data-origin-width=&quot;550&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;http://blog.naver.com/rhkdtls8092/220260842686&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;메인 프로젝트를 시작하기 전 ZEP에서 팀원을 구하는 모습은 마치 옛날의 메xx 자유시장 같은 모습이었다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size14&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;애견 관심 있으신 분들 찾아요@@@@&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;지금 팀의 팀장님의 글이 눈에 띄어 바로 말씀드리고 팀에 합류했다. 팀 당 FE 3 / BE 3 기준이었는데 합류하자마자 자리가 꽉 차서 조금만 고민했으면 합류하지 못할 뻔했다.. 이렇게 모인 팀원들은 다 강아지를 키우거나 키운 경험이 있었고 그렇게 팀 이름은 &lt;b&gt;동물 특공대&lt;/b&gt;가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;정규시간 외에도 작업 내용을 공유하면서 늦은 시간까지 회의해도 힘들지 않았고 이보다 더 좋은 프론트 분들이 계실까 싶을 정도의 페이지를 만들어주신 분들과 마음 잘 맞는 백엔드 분들 덕분에 4주가 재밌고 빠르게 지나갔다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;지도 Modal 부분&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Modal.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1200&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t2LCU/btrYeZPnOko/DPhTNlfhRGLRL8K85Wj4CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t2LCU/btrYeZPnOko/DPhTNlfhRGLRL8K85Wj4CK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t2LCU/btrYeZPnOko/DPhTNlfhRGLRL8K85Wj4CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft2LCU%2FbtrYeZPnOko%2FDPhTNlfhRGLRL8K85Wj4CK%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;1920&quot; height=&quot;1200&quot; data-filename=&quot;Modal.png&quot; data-origin-width=&quot;1920&quot; data-origin-height=&quot;1200&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;size14&quot;&gt;아무것도 없는 단계에서 기획부터 구현까지 해야 하는 메인 프로젝트를 통해&amp;nbsp; 일단 하면 어떻게든 된다! 라는 자신감 같은 것이 생겼고 데모데이 때는 다른 팀들이 만든 결과물을 보면서 이런 기능도 넣었네 나도 다른 프로젝트에 사용해 보고 싶다는 생각을 하는 시간이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;수료 후에도 힘내서 달려보자!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image.png&quot; data-origin-width=&quot;265&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/N3cTO/btrYjzXZhgW/iPXC1jeEgX3ZrXhujtfkn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/N3cTO/btrYjzXZhgW/iPXC1jeEgX3ZrXhujtfkn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/N3cTO/btrYjzXZhgW/iPXC1jeEgX3ZrXhujtfkn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FN3cTO%2FbtrYjzXZhgW%2FiPXC1jeEgX3ZrXhujtfkn1%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;265&quot; height=&quot;150&quot; data-filename=&quot;image.png&quot; data-origin-width=&quot;265&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;동물특공대 노션 페이지&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://codestates.notion.site/b2495985e7ed43c2b497f03517018556&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://codestates.notion.site/b2495985e7ed43c2b497f03517018556&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1675649863615&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;  동물 특공대  &quot; data-og-description=&quot;✉️&amp;nbsp;commit message&quot; data-og-host=&quot;codestates.notion.site&quot; data-og-source-url=&quot;https://codestates.notion.site/b2495985e7ed43c2b497f03517018556&quot; data-og-url=&quot;https://codestates.notion.site/b2495985e7ed43c2b497f03517018556&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dNWPUP/hyRwB1feas/kJ0Hs45mrX6PPRmuk35O51/img.jpg?width=2000&amp;amp;height=1332&amp;amp;face=0_0_2000_1332,https://scrap.kakaocdn.net/dn/f1BW9/hyRwJE0uBa/11GrkW0usCOpZ3pEQrAepK/img.jpg?width=2000&amp;amp;height=1332&amp;amp;face=0_0_2000_1332&quot;&gt;&lt;a href=&quot;https://codestates.notion.site/b2495985e7ed43c2b497f03517018556&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://codestates.notion.site/b2495985e7ed43c2b497f03517018556&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dNWPUP/hyRwB1feas/kJ0Hs45mrX6PPRmuk35O51/img.jpg?width=2000&amp;amp;height=1332&amp;amp;face=0_0_2000_1332,https://scrap.kakaocdn.net/dn/f1BW9/hyRwJE0uBa/11GrkW0usCOpZ3pEQrAepK/img.jpg?width=2000&amp;amp;height=1332&amp;amp;face=0_0_2000_1332');&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;  동물 특공대  &lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;✉️&amp;nbsp;commit message&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;codestates.notion.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PAWPWA 배포 사이트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;http://pawpaw.com.s3-website.ap-northeast-2.amazonaws.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;http://pawpaw.com.s3-website.ap-northeast-2.amazonaws.com&lt;/a&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PAWPAW 깃 허브&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://github.com/khd325/PAWPAW&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/khd325/PAWPAW&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1675649933376&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - khd325/PAWPAW&quot; data-og-description=&quot;Contribute to khd325/PAWPAW development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/khd325/PAWPAW&quot; data-og-url=&quot;https://github.com/khd325/PAWPAW&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bkoZ3S/hyRwugLYR2/XhfBaNLEVZks9U0RKQgTX0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/khd325/PAWPAW&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/khd325/PAWPAW&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bkoZ3S/hyRwugLYR2/XhfBaNLEVZks9U0RKQgTX0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - khd325/PAWPAW&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to khd325/PAWPAW development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;팀 소개.PNG&quot; data-origin-width=&quot;771&quot; data-origin-height=&quot;875&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r6Sal/btrYfZ9ylOy/19iNtmUjk1ZZ4EfumxwRS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r6Sal/btrYfZ9ylOy/19iNtmUjk1ZZ4EfumxwRS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r6Sal/btrYfZ9ylOy/19iNtmUjk1ZZ4EfumxwRS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr6Sal%2FbtrYfZ9ylOy%2F19iNtmUjk1ZZ4EfumxwRS0%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;771&quot; height=&quot;875&quot; data-filename=&quot;팀 소개.PNG&quot; data-origin-width=&quot;771&quot; data-origin-height=&quot;875&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스택.png&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh2Pd5/btrYdiIjRwO/kCaRWjTGSsDOoyq4K4krGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh2Pd5/btrYdiIjRwO/kCaRWjTGSsDOoyq4K4krGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh2Pd5/btrYdiIjRwO/kCaRWjTGSsDOoyq4K4krGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbh2Pd5%2FbtrYdiIjRwO%2FkCaRWjTGSsDOoyq4K4krGK%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;1070&quot; height=&quot;788&quot; data-filename=&quot;스택.png&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>회고</category>
      <category>PAWPAW</category>
      <category>동물 특공대</category>
      <category>메인 프로젝트</category>
      <category>코드스테이츠</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/41</guid>
      <comments>https://dongs-record.tistory.com/41#entry41comment</comments>
      <pubDate>Mon, 6 Feb 2023 11:20:33 +0900</pubDate>
    </item>
    <item>
      <title>[Security] JJWT 라이브러리 Jwts.builder().setSubject null 문제</title>
      <link>https://dongs-record.tistory.com/40</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;JWT와 redis를 이용해서 토큰 재발급 로직을 작성하다 만난 에러&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1673194089188&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void reIssue(AuthRequestDto.ReIssue reIssue, HttpServletResponse response) {
        //Refresh Token 검증
        if (!jwtTokenProvider.validateToken(reIssue.getRefreshToken())) {
            throw new BusinessLogicException(ExceptionCode.INVALID_TOKEN);
        }

        String accessToken = jwtTokenProvider.resolveToken(reIssue.getAccessToken());

        //AccessToken으로 Authentication 생성
        Authentication authentication = jwtTokenProvider.getAuthentication(accessToken);
        
        //...
}


public Authentication getAuthentication(String accessToken) {
        //...
        UserDetails principal = new User(claims.getSubject(), &quot;&quot;, authorities);

        return new UsernamePasswordAuthenticationToken(principal, &quot;&quot;, authorities);
    }

public AuthResponseDto.TokenInfo generateToken(Map&amp;lt;String,Object&amp;gt; claims, String subject) {


        //..

        System.out.println(subject);
        String accessToken = Jwts.builder()
                .setSubject(subject)
                .setClaims(claims)
                .setExpiration(accessTokenExpiresIn)
                .signWith(key)
                .compact();
                
        //...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;위와 같은 로직으로 작성했는데 로그인 요청에 대한 처리로 AccessToken과 RefreshToken은 정상발급 되는데 재발급 요청에선 다음과 같은 에러가 찍히면서 authentication객체가 만들어지지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;java.lang.IllegalArgumentException: Cannot pass null or empty values to constructor&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;1124&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tCpUM/btrVK0bVIgO/mqDfrwmlmK1iQkqW1Tl3rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tCpUM/btrVK0bVIgO/mqDfrwmlmK1iQkqW1Tl3rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tCpUM/btrVK0bVIgO/mqDfrwmlmK1iQkqW1Tl3rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtCpUM%2FbtrVK0bVIgO%2FmqDfrwmlmK1iQkqW1Tl3rk%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;1124&quot; height=&quot;212&quot; data-origin-width=&quot;1124&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;디버깅을 해보니 토큰을 발행할 때 setsubject가 적용되지 않았고 토큰 claims에 subject가 없어서 authentication 객체를 만들지 못했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;해결방법은 간단했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Jwts.builder()
                .setClaims(claims)
                .setSubject(subject)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;setClaims를 setSubject보다 먼저 적용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://github.com/jwtk/jjwt/issues/179&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/jwtk/jjwt/issues/179&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;1097&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfI0Mo/btrVK0Xj4bS/8OFYFldv30PwqnJgh9YOP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfI0Mo/btrVK0Xj4bS/8OFYFldv30PwqnJgh9YOP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfI0Mo/btrVK0Xj4bS/8OFYFldv30PwqnJgh9YOP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfI0Mo%2FbtrVK0Xj4bS%2F8OFYFldv30PwqnJgh9YOP0%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;1097&quot; height=&quot;150&quot; data-origin-width=&quot;1097&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20180607225725_f.jpg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmDnKq/btrVzYtEj9L/K8HwSXZBmxgBObpraATvm0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmDnKq/btrVzYtEj9L/K8HwSXZBmxgBObpraATvm0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmDnKq/btrVzYtEj9L/K8HwSXZBmxgBObpraATvm0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmDnKq%2FbtrVzYtEj9L%2FK8HwSXZBmxgBObpraATvm0%2Fimg.jpg&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;197&quot; data-filename=&quot;20180607225725_f.jpg&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;263&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>Programming/Security</category>
      <category>jjwt</category>
      <category>Spring Security</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/40</guid>
      <comments>https://dongs-record.tistory.com/40#entry40comment</comments>
      <pubDate>Mon, 9 Jan 2023 01:22:58 +0900</pubDate>
    </item>
    <item>
      <title>[Network] nginx reverse proxy, redirect 적용</title>
      <link>https://dongs-record.tistory.com/39</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;환경 : ec2 (ubuntu 18.04), spring boot, nginx/1.14.0(ubuntu), certbot으로 domain https 인증서 발급&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;certbot https 인증서 발급 참고 블로그&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a title=&quot;HTTPS 인증서 발급&quot; href=&quot;https://junho85.pe.kr/2048&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://junho85.pe.kr/2048&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;- sudo mkdir /var/log/nginx/proxy/&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; # log, error 파일용 디렉토리&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;- sudo vi /etc/nginx/proxy_params 아래 코드 작성&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;proxy_set_header&amp;nbsp;X-Real-IP&amp;nbsp;$remote_addr; &lt;br /&gt;proxy_set_header&amp;nbsp;X-Forwarded-For&amp;nbsp;$proxy_add_x_forwarded_for; &lt;br /&gt;proxy_set_header&amp;nbsp;Host&amp;nbsp;$http_host; &lt;br /&gt;proxy_set_header&amp;nbsp;X-Forwarded-Proto&amp;nbsp;$scheme; &lt;br /&gt;proxy_set_header&amp;nbsp;X-NginX-Proxy&amp;nbsp;true; &lt;br /&gt;&lt;br /&gt;client_max_body_size&amp;nbsp;256M; &lt;br /&gt;client_body_buffer_size&amp;nbsp;1m; &lt;br /&gt;&lt;br /&gt;proxy_buffering&amp;nbsp;on; &lt;br /&gt;proxy_buffers&amp;nbsp;256&amp;nbsp;16k; &lt;br /&gt;proxy_buffer_size&amp;nbsp;128k; &lt;br /&gt;proxy_busy_buffers_size&amp;nbsp;256k; &lt;br /&gt;&lt;br /&gt;proxy_temp_file_write_size&amp;nbsp;256k; &lt;br /&gt;proxy_max_temp_file_size&amp;nbsp;1024m; &lt;br /&gt;&lt;br /&gt;proxy_connect_timeout&amp;nbsp;300; &lt;br /&gt;proxy_send_timeout&amp;nbsp;300; &lt;br /&gt;proxy_read_timeout&amp;nbsp;300; &lt;br /&gt;proxy_intercept_errors&amp;nbsp;on;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;sudi vi /etc/nginx/nginx.conf 안에&lt;br /&gt;http {&lt;br /&gt;&amp;nbsp; &amp;nbsp; server_names hash_bucke_size64; #주석 제거&lt;br /&gt;}&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;- sudo vi /etc/nginx/sites-available/&lt;span style=&quot;color: #ee2323;&quot;&gt;{domain}&lt;/span&gt; 아래 코드 작성&amp;nbsp; &lt;span style=&quot;color: #ee2323;&quot;&gt;{domain} : example.co.kr(com, site, ...)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;server&amp;nbsp;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;listen&amp;nbsp;80; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;server_name &lt;span style=&quot;color: #ee2323;&quot;&gt;{domain}&lt;/span&gt; www.&lt;span style=&quot;color: #ee2323;&quot;&gt;{domain}&lt;/span&gt;&lt;a href=&quot;http://www.hyeon-dong.site;&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;;&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;access_log&amp;nbsp;/var/log/nginx/proxy/access.log; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_log&amp;nbsp;/var/log/nginx/proxy/error.log; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return 301 https://&lt;span style=&quot;color: #ee2323;&quot;&gt;{domain}&lt;/span&gt;$request_uri;&amp;nbsp; &amp;nbsp; # 80번 포트요청은 443으로 redirect&lt;br /&gt;} &lt;br /&gt;&lt;br /&gt;server&amp;nbsp;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;listen&amp;nbsp;443&amp;nbsp;ssl; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;server_name &lt;span style=&quot;color: #ee2323;&quot;&gt;{domain}&lt;/span&gt;; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ssl_certificate /etc/letsencrypt/live/&lt;span style=&quot;color: #ee2323;&quot;&gt;{domain}&lt;/span&gt;/fullchain.pem; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ssl_certificate_key /etc/letsencrypt/live/&lt;span style=&quot;color: #ee2323;&quot;&gt;{domain}&lt;/span&gt;/privkey.pem; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;include&amp;nbsp;/etc/letsencrypt/options-ssl-nginx.conf;&amp;nbsp;#&amp;nbsp;managed&amp;nbsp;by&amp;nbsp;Certbot &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ssl_dhparam&amp;nbsp;/etc/letsencrypt/ssl-dhparams.pem;&amp;nbsp;#&amp;nbsp;managed&amp;nbsp;by&amp;nbsp;Certbot &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;access_log&amp;nbsp;/var/log/nginx/proxy/access.log; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;error_log&amp;nbsp;/var/log/nginx/proxy/error.log; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;location&amp;nbsp;/&amp;nbsp;{ &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;include&amp;nbsp;/etc/nginx/proxy_params; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;proxy_pass http://localhost:8080; #요청&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;} &lt;br /&gt;}&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;sudo ln -s /etc/nginx/sites-available/&lt;span style=&quot;color: #ee2323;&quot;&gt;{domain}&lt;/span&gt; /etc/nginx/sites-enabled/&lt;/span&gt; 명령어로 심 링크 설정&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;sudo rm /etc/nginx/sites-available/default&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;sudo rm /etc/nginx/sites-enabled/default&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;sudo nginx -t&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;sudo service nginx reload 후 jar 파일 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;&lt;a href=&quot;https://community.letsencrypt.org/t/nginx-certbot-redirect-https-www-to-https/142678&quot;&gt;https://community.letsencrypt.org/t/nginx-certbot-redirect-https-www-to-https/142678&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #666666;&quot;&gt;&lt;a href=&quot;https://velog.io/@u-nij/Spring-Boot-Nginx-%EC%97%B0%EB%8F%99%ED%95%B4%EC%84%9C-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0&quot;&gt;https://velog.io/@u-nij/Spring-Boot-Nginx-%EC%97%B0%EB%8F%99%ED%95%B4%EC%84%9C-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Computer Science/Network</category>
      <category>EC2</category>
      <category>Network</category>
      <category>nginx</category>
      <category>기록용</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/39</guid>
      <comments>https://dongs-record.tistory.com/39#entry39comment</comments>
      <pubDate>Wed, 21 Dec 2022 20:26:26 +0900</pubDate>
    </item>
    <item>
      <title>[Security] Spring Security 인증 처리 과정</title>
      <link>https://dongs-record.tistory.com/38</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Spring Security 인증 처리 과정&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;authentication.png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1065&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qKNsf/btrSxlYyXvb/x563fOCR1BkOEdG3vMBG41/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qKNsf/btrSxlYyXvb/x563fOCR1BkOEdG3vMBG41/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qKNsf/btrSxlYyXvb/x563fOCR1BkOEdG3vMBG41/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqKNsf%2FbtrSxlYyXvb%2Fx563fOCR1BkOEdG3vMBG41%2Fimg.jpg&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;1440&quot; height=&quot;1065&quot; data-filename=&quot;authentication.png&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;1065&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Authentication.jpg&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;718&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBHk1C/btrSyTAjFN2/FnbT5Tl38ItFr7VsTeh1Q0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBHk1C/btrSyTAjFN2/FnbT5Tl38ItFr7VsTeh1Q0/img.jpg&quot; data-alt=&quot;https://www.javainuse.com/webseries/spring-security-jwt/chap3&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBHk1C/btrSyTAjFN2/FnbT5Tl38ItFr7VsTeh1Q0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBHk1C%2FbtrSyTAjFN2%2FFnbT5Tl38ItFr7VsTeh1Q0%2Fimg.jpg&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;1050&quot; height=&quot;718&quot; data-filename=&quot;Authentication.jpg&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;718&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.javainuse.com/webseries/spring-security-jwt/chap3&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;- 로그인 요청&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;- AuthenticationFilter에서 username과 password로 Authentication(&lt;b&gt;인증되지 않은&lt;/b&gt;) 객체 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;- Authentication 객체를 AuthenticationManager에 전달&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;AuthenticationManager는 인증 처리 역할을 하는 인터페이스, 인증을 위한 실질적인 관리는 AuthenticationManager를 구현하는 클래스&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(ProviderManager) 를 통해 이루어짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;- ProviderManager로부터 전달받은 Authentication을 AuthenticationProvider는 UserDetailsService를 이용해 UserDetails 조회&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;- AuthenticationProvider는 전달받은 UserDetails를 이용해서 검증하고 검증에 성공하면 인증된 Authentication 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;- AuthenticationFilter까지 전달된 Authentication은 SecurityContext에 저장&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인증 컴포넌트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. UsernamePasswordAuthenticationFilter&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;request를 제일 먼저 만나는 컴포넌트, AbstractAuthenticationProcessingFilter 상속&lt;/p&gt;
&lt;pre id=&quot;code_1669818266560&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

	//...

	public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
		super(DEFAULT_ANT_PATH_REQUEST_MATCHER, authenticationManager);
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException {
		if (this.postOnly &amp;amp;&amp;amp; !request.getMethod().equals(&quot;POST&quot;)) {
			throw new AuthenticationServiceException(&quot;Authentication method not supported: &quot; + request.getMethod());
		}
		String username = obtainUsername(request);
		username = (username != null) ? username.trim() : &quot;&quot;;
		String password = obtainPassword(request);
		password = (password != null) ? password : &quot;&quot;;
		UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(username,
				password);
		// Allow subclasses to set the &quot;details&quot; property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;attemptAuthentication 메서드에서 usernamePasswordAuthenticationToken 생성 (인증에 사용되는 토큰)&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;토큰을 생성하고 AuthenticationManager의 authenticate 메서드를 호출해서 인증 처리 위임&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. AuthenticationManager&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;인증 처리를 총괄하는 인터페이스&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public interface AuthenticationManager {
   Authentication authenticate(Authentication authentication) throws AuthenticationException;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. ProviderManager&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;적절한 AuthenticationProvider를 찾아서 AuthenticationProvider에 인증 처리 위임&lt;/p&gt;
&lt;pre id=&quot;code_1669820262545&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
	//...
    
	public ProviderManager(List&amp;lt;AuthenticationProvider&amp;gt; providers, AuthenticationManager parent) {
		Assert.notNull(providers, &quot;providers list cannot be null&quot;);
		this.providers = providers;
		this.parent = parent;
		checkState();
	}

	//...
    
	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		Class&amp;lt;? extends Authentication&amp;gt; toTest = authentication.getClass();
		AuthenticationException lastException = null;
		AuthenticationException parentException = null;
		Authentication result = null;
		Authentication parentResult = null;
		int currentPosition = 0;
		int size = this.providers.size();
		for (AuthenticationProvider provider : getProviders()) {
			if (!provider.supports(toTest)) {
				continue;
			}
			if (logger.isTraceEnabled()) {
				logger.trace(LogMessage.format(&quot;Authenticating request with %s (%d/%d)&quot;,
						provider.getClass().getSimpleName(), ++currentPosition, size));
			}
			try {
				result = provider.authenticate(authentication);
				if (result != null) {
					copyDetails(authentication, result);
					break;
				}
			}
			catch (AccountStatusException | InternalAuthenticationServiceException ex) {
				prepareException(ex, authentication);
				// SEC-546: Avoid polling additional providers if auth failure is due to
				// invalid account status
				throw ex;
			}
			catch (AuthenticationException ex) {
				lastException = ex;
			}
		}
		if (result == null &amp;amp;&amp;amp; this.parent != null) {
			try {
				parentResult = this.parent.authenticate(authentication);
				result = parentResult;
			}
			catch (ProviderNotFoundException ex) {

			}
			catch (AuthenticationException ex) {
				parentException = ex;
				lastException = ex;
			}
		}
		if (result != null) {
			if (this.eraseCredentialsAfterAuthentication &amp;amp;&amp;amp; (result instanceof CredentialsContainer)) {
				((CredentialsContainer) result).eraseCredentials();
			}
			if (parentResult == null) {
				this.eventPublisher.publishAuthenticationSuccess(result);
			}

			return result;
		}

		//...
	}

	//...

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. AuthenticationProvider&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;UserDetailsService로부터 전달받은 UserDetails를 이용해서 인증 처리&lt;/p&gt;
&lt;pre id=&quot;code_1669820672106&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
	//...

	@Override
	@SuppressWarnings(&quot;deprecation&quot;)
	protected void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
		if (authentication.getCredentials() == null) {
			this.logger.debug(&quot;Failed to authenticate since no credentials provided&quot;);
			throw new BadCredentialsException(this.messages
					.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.badCredentials&quot;, &quot;Bad credentials&quot;));
		}
		String presentedPassword = authentication.getCredentials().toString();
		if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
			this.logger.debug(&quot;Failed to authenticate since password does not match stored value&quot;);
			throw new BadCredentialsException(this.messages
					.getMessage(&quot;AbstractUserDetailsAuthenticationProvider.badCredentials&quot;, &quot;Bad credentials&quot;));
		}
	}

	//...

	@Override
	protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
		prepareTimingAttackProtection();
		try {
			UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
			if (loadedUser == null) {
				throw new InternalAuthenticationServiceException(
						&quot;UserDetailsService returned null, which is an interface contract violation&quot;);
			}
			return loadedUser;
		}
		catch (UsernameNotFoundException ex) {
			mitigateAgainstTimingAttack(authentication);
			throw ex;
		}
		catch (InternalAuthenticationServiceException ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new InternalAuthenticationServiceException(ex.getMessage(), ex);
		}
	}

	//...

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;additionalAuthenticationChecks 메서드에서 password 검증&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #262f40;&quot;&gt;retrieveUser 메서드는 UserDetails를 조회하고 인증에 성공하면 반환&lt;/span&gt;&lt;/p&gt;</description>
      <category>Programming/Security</category>
      <category>Spring Security</category>
      <category>인증</category>
      <author>hdk325</author>
      <guid isPermaLink="true">https://dongs-record.tistory.com/38</guid>
      <comments>https://dongs-record.tistory.com/38#entry38comment</comments>
      <pubDate>Thu, 1 Dec 2022 00:12:28 +0900</pubDate>
    </item>
  </channel>
</rss>