<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>점이 모여 선이 된다</title>
    <link>https://xandxlass.tistory.com/</link>
    <description>꾸준함을 지향합니다</description>
    <language>ko</language>
    <pubDate>Fri, 14 Aug 2026 23:15:11 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>xandxlass</managingEditor>
    <image>
      <title>점이 모여 선이 된다</title>
      <url>https://tistory1.daumcdn.net/tistory/6509773/attach/5727216a49b04415a89cec193b901395</url>
      <link>https://xandxlass.tistory.com</link>
    </image>
    <item>
      <title>스프링 핵심 원리-기본편 섹션 4.스프링 컨테이너와 스프링 빈</title>
      <link>https://xandxlass.tistory.com/142</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;컨테이너에 등록된 모든 빈 조회&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;빈 이름으로 조회할 경우&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;빈 이름으로 조회&quot;)
void findBeanByName() {
    MemberService memberService = ac.getBean(&quot;memberService&quot;, MemberService.class); //MemberService, 즉 인터페이스로 조회함 그러면 이 인터페이스의 구현체가 대상이 된다
    assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
    //isInstanceOf() 연산자:해당 타입의 인스턴스인지를 비교하는 메서드, 객체가 특정클래스나 인터페이스로부터 생성된 것인지를 판별
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;멤버서비스가 멤버 서비스 인플의 인스턴스면 성공&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;구체 타입으로 조회할 경우&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;구체 타입으로 조회&quot;)
void findBeanByName2() {
    MemberService memberService = ac.getBean(&quot;memberService&quot;, MemberServiceImpl.class); //스프링 컨테이너에 MemberServiceImpl이 등록되어있으면 조회가 됨
    assertThat(memberService).isInstanceOf(MemberServiceImpl.class);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration
public class AppConfig { //나의 애플리케이션 전체에 대해 설정하고 구성하는 공간

    //멤버서비스에 대한 구현을 나의 애플리케이션에서는 멤버서비스 인플을 쓸거야
    @Bean
    public MemberService memberService() { //AppCofig를 쓸때 멤버서비스 씀
        return new MemberServiceImpl(MemberRepository()); //멤버서비스 구현체인 객체가 생성됨
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;반환타입 MemberService이 아니라 MemberServiceImpl해도 상관없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스프링빈에 등록된 인스턴스 타입을 보고 결정하기 때문에 꼭 여기있는 인터페이스( MemberService) 아니어도 된다. MemberServiceImpl 해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/** &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;구체적인건&amp;nbsp;좋지&amp;nbsp;않다 &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;의존해야한다. &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*&amp;nbsp;근데&amp;nbsp;이건&amp;nbsp;구현에&amp;nbsp;의존한게됨 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;*/&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;빈 이름으로 조회할 경우&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;빈 이름으로 조회X&quot;)
void findBeanNameX() { //항상 성공테스트뿐만 아니라 실패 테스트도 만들어야함
    MemberService xxxx = ac.getBean(&quot;xxxxx&quot;, MemberService.class);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/20u5J/btsF3osQ82L/KNXYm8Tup6NwepfkJl1dnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/20u5J/btsF3osQ82L/KNXYm8Tup6NwepfkJl1dnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/20u5J/btsF3osQ82L/KNXYm8Tup6NwepfkJl1dnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F20u5J%2FbtsF3osQ82L%2FKNXYm8Tup6NwepfkJl1dnK%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;1348&quot; height=&quot;352&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;NoSuchBeanDefinitionException : No bean named 'xxxxx' available 에러가 뜬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;빈 이름으로 조회X&quot;)
void findBeanNameX() { //항상 성공테스트뿐만 아니라 실패 테스트도 만들어야함
    assertThrows(NoSuchBeanDefinitionException.class,
            () -&amp;gt; ac.getBean(&quot;xxxxx&quot;, MemberService.class));  //무조건 이 예외가 터져야 성공한다는 뜻  static import : 알트+엔터

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;() -&amp;gt; ac.getBean(&quot;xxxxx&quot;, MemberService.class)이 실행되면 NoSuchBeanDefinitionException.class 예외가 실행되어야 한다. 이 예외가 터지면 성공, 아니면 실패&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;동일한 타입이 둘 이상&lt;/h2&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;class ApplicationContextSameBeanFindTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SameBeanConfig.class);

    @Test
    @DisplayName(&quot;타입으로 조회시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다&quot;)
    void findBeanByTypeDuplicate() {
        MemberRepository bean = ac.getBean(MemberRepository.class); //타입만 지정한 경우 예외 생김
    }

    @Configuration
    static class SameBeanConfig { //테스트하려고 하는거니까 AppConfig를 손대지 않고 안에서만 쓰기 위해 SameBeanConfig를 만듦
        //클래스 안에서 static을 쓴다는건 이 안에서만 쓰겠다는 뜻
        @Bean //빈의 이름이 다르고 인스턴스 타입이 같을 수 있다
        public MemberRepository memberRepository1() {
            return new MemoryMemberRepository();
        }

        @Bean
        public MemberRepository memberRepository2() {
            return new MemoryMemberRepository();
        }
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1777&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DGSkn/btsF3maNBbV/dlKLq9zU2FTW2286V4vlLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DGSkn/btsF3maNBbV/dlKLq9zU2FTW2286V4vlLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DGSkn/btsF3maNBbV/dlKLq9zU2FTW2286V4vlLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDGSkn%2FbtsF3maNBbV%2FdlKLq9zU2FTW2286V4vlLK%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;1777&quot; height=&quot;408&quot; data-origin-width=&quot;1777&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;NoUniqueBeanDefinitionException 유니크 하지 않다, 즉 중복이 있다는 예외가 발생함&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스프링 빈 조회 - 상속 관계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;1.반환타입이 DiscountPolicy&lt;span&gt; 일 경우&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;@Bean
public DiscountPolicy rateDiscountPoilicy(){
    return new RateDiscountPolicy();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2.반환타입이 RateDiscountPolicy &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;일 경우&lt;/span&gt;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;@Bean
public RateDiscountPolicy rateDiscountPoilicy(){
    return new RateDiscountPolicy();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;DiscountPolicy, RateDiscountPolicy 모두 가능하지만 역할과 구현을 나누는 측면에서 1번이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;반환타입을 보고 역할을 알 수 있다. DI하고 있을때도 활용하기 쉽게 1번이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;부모 타입으로 모두 조회하기&quot;)
void findAllBeanByParentType() {
    Map&amp;lt;String, DiscountPolicy&amp;gt; beansOfType = ac.getBeansOfType(DiscountPolicy.class);
    assertThat(beansOfType.size()).isEqualTo(2);

    for (String key : beansOfType.keySet()) {
        System.out.println(&quot;key = &quot; + key+&quot;value = &quot;+beansOfType.get(key));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;테스트 할때 println 안하는게 좋다. 자동 통과/실패를 시스템이 결정하도록 해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;테스트 디버깅할때는 괜찮다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;부모타입으로 모두 조회하기 - Object&quot;)
void findAllBeanByObjectType() {
    Map&amp;lt;String, Object&amp;gt; beansOfType = ac.getBeansOfType(Object.class);
    for (String key : beansOfType.keySet()) {
        System.out.println(&quot;key = &quot; + key+&quot;value = &quot;+beansOfType.get(key));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l2XiU/btsF5CRSk9O/T52ejvylFOVx58SfyV6Ke1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l2XiU/btsF5CRSk9O/T52ejvylFOVx58SfyV6Ke1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l2XiU/btsF5CRSk9O/T52ejvylFOVx58SfyV6Ke1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2XiU%2FbtsF5CRSk9O%2FT52ejvylFOVx58SfyV6Ke1%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;1768&quot; height=&quot;472&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스프링 여러가지 빈들이 등록 된게 다 나온다. 왜냐하면 Java 객체는 모든게 Object 타입이기 때문이다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;실제로 getBean을 쓸 일은 없지만 기본기능이고 순수한 Java 어플리케이션에서 스프링컨테이너를 생성해서 써야할 일이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;BeanFactory와 ApplicationContext&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;환경변수: 로컬, 개발, 운영 등을 구분해서 처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;로컬 환경:처음 내 PC에서 개발한 환경&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;개발 환경:여러 시스템을 엮어서 실제&amp;nbsp; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;테스트 서버에 띄워두고 테스트할 수 있는 테스트 서버&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;운영 환경: 실제 프로덕션에 나가는 운영환경&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;스테이징 환경:운영과 가장 비슷한 밀접한 환경&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;각 환경별로 어떤 데이터베이스에 연결해야할 지, 그런 환경변수와 관련된 정보를 처리해주는 기능을 제공함&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;편리한 리소스 조회: 파일을 읽어서 내부에서 쓸 때 추상화해서 편리하게 쓸 수 있는 기능 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스프링 빈 설정 메타 정보 - BeanDefinition&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;BeanDefinition에 빈의 메타정보를 담는다&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;appConfig를 가지고 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;BeanDefinition 설정정보를 만든다 bin 당 하나의 설정정보다&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public class BeanDefinitionTest {
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName(&quot;빈 설정 메타정보 확인&quot;)
    void findApplicationBean() {
        String[] beanDefinitionNames = ac.getBeanDefinitionNames(); //이름 가져오기
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);

            if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
                System.out.println(&quot;beanDefinition = &quot; + beanDefinition +
                        &quot;beanDefinition = &quot;+ beanDefinition);
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1773&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEP6QO/btsF5Fnqvns/izVp9JiPXqOPdw3uNknqu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEP6QO/btsF5Fnqvns/izVp9JiPXqOPdw3uNknqu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEP6QO/btsF5Fnqvns/izVp9JiPXqOPdw3uNknqu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEP6QO%2FbtsF5Fnqvns%2FizVp9JiPXqOPdw3uNknqu1%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;1773&quot; height=&quot;345&quot; data-origin-width=&quot;1773&quot; data-origin-height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;출력 결과가 에서 scope 가 할당이 안되어 있으면 싱글톤&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;abstract, lazy : 보통 스프링 빈들이 스프링 컨테이너가 뜰 때 다 등록이 되는데 그게 아니라 실제 사용하는 시점에 나중에 실제 사용하는 시점에 스프링빈을 초기화해 라는 정보&lt;/p&gt;
&lt;pre id=&quot;code_1711417671108&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;factoryBeanName=appConfig; factoryMethodName=memberService;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;appConfig에 있는 memberService를 호출해서 실제 빈을 생성할 수 있구나 라는 뜻&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이런 정보들이 있다는 정도만 이해&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이런 메타정보를 기반으로 인스턴스를 생성함&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스프링 빈을 만들때는 1. 직접적으로 스프링 빈을 등록하는 방법 2. 팩토리 빈으로 등록하는 방식(Java config)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/142</guid>
      <comments>https://xandxlass.tistory.com/142#entry142comment</comments>
      <pubDate>Tue, 26 Mar 2024 10:58:21 +0900</pubDate>
    </item>
    <item>
      <title>스프링 핵심 원리-기본편 섹션 3. 스프링 핵심 원리 이해2 정리</title>
      <link>https://xandxlass.tistory.com/141</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;관심사 분리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;MemberApp&amp;nbsp;변경전&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class MemberApp {
    public static void main(String[] args) {
        MemberService memberService = new MemberServiceImpl();
        Member member = new Member(1L, &quot;memberA&quot;, Grade.VIP);
        memberService.join(member);

        Member findMember = memberService.findMember(1L);
        System.out.println(&quot;findMember = &quot; + member.getName());
        System.out.println(&quot;findMember = &quot; + findMember.getName());

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변경코드&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    AppConfig appConfig = new AppConfig(); //이거 무조건 만들어야댐
    MemberService memberService = appConfig.memberService();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이하 동일&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변경 전 코드는 멤버서비스 인플에서 메모리 멤버 리파지토리를 만드는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변경 후 코드는 appConfig에서 다 결정한다. appConfig가 멤버서비스 인플을 반환을 하니까 memberService에는 멤버서비스 인플이 들어가있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;OrderApp&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    AppConfig appConfig = new AppConfig();
    MemberService memberService = appConfig.memberService();
    OrderService orderService = appConfig.orderService();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;AppConfig&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public OrderService orderService() {
    return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy()); //AppConfig에서 구현객체를 생성함
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;OrderApp의 orderService를 보자&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;AppConfig에서 OrderServiceImpl 객체가 생성되고 MemoryMemberRepository와 FixDiscountPolicy가 생성자로 넘어간다 OrderServiceImpl이 MemoryMemberRepository와 FixDiscountPolicy객체를 참조하도록 하고 완성된 OrderServiceImpl 객체를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;MemberServiceTest 변경 전&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;public class MemberServiceTest {
    MemberService memberService = new MemberServiceImpl();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변경 후&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class MemberServiceTest {
    MemberService memberService;

    @BeforeEach
    public void beforeEach() { //테스트 실행하기 전에 수행됨
        AppConfig appConfig = new AppConfig();
        memberService = appConfig.memberService();
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;팁 컨트롤 + E + 엔터 : 이전에 했던 파일로 돌아감&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AppConfig 리팩터링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;역할에 따른 어떤 구현을 하는지가 한눈에 보여야한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AWUeA/btsFYLWkbVO/IBya9MU4HjBYFkKgX3kKWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AWUeA/btsFYLWkbVO/IBya9MU4HjBYFkKgX3kKWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AWUeA/btsFYLWkbVO/IBya9MU4HjBYFkKgX3kKWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAWUeA%2FbtsFYLWkbVO%2FIBya9MU4HjBYFkKgX3kKWk%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;926&quot; height=&quot;316&quot; data-origin-width=&quot;926&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;팁:컨트롤 + 알트 + M : 리팩토링할때 중복제거&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class AppConfig { //나의 애플리케이션 전체에 대해 설정하고 구성하는 공간
    public MemberService memberService() { //AppCofig를 쓸때 멤버서비스 씀
        return new MemberServiceImpl(MemberRepository()); //멤버서비스 구현체인 객체가 생성됨
    }

    private MemoryMemberRepository MemberRepository() {
        return new MemoryMemberRepository();
    }

    public OrderService orderService() {
        return new OrderServiceImpl(MemberRepository(), discountPolicy()); //AppConfig에서 구현객체를 생성함
    }

    public DiscountPolicy discountPolicy() {
        return new FixDiscountPolicy();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;리팩토링을 통해 MemberService 역할, MemoryMemberRepository 역할, OrderService 역할, discountPolicy 역할이 드러나게 된다. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;OrderService&lt;span&gt; 에서 discountPolicy()를 둠으로써 FixDiscountPolicy()를 콜하도록 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;이점:메소드명만 봐도 역할이 잘 드러나게 된다. 애플리케이션 전체 구성이 어떻게 되어있는지 빠르게 파악할 수 있다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;새로운 구조와 할인 정책 적용&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;AppCofing:구체적인거에 대해서 잘 아는 책임&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;591&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8MiDA/btsFYCyu1sg/C1TA1sj4SR8kamxYk22KR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8MiDA/btsFYCyu1sg/C1TA1sj4SR8kamxYk22KR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8MiDA/btsFYCyu1sg/C1TA1sj4SR8kamxYk22KR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8MiDA%2FbtsFYCyu1sg%2FC1TA1sj4SR8kamxYk22KR0%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;837&quot; height=&quot;591&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;591&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;너무 중요한 그림!&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;사용영역에 있는 코드는 전혀 손대지 않고 구성 영역의 코드만 바꿀 수 있다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;IoC, DI, 그리고 컨테이너&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;630&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVBnVm/btsF1i6KJgx/auexoSCXU1Kk9dJCByh6zK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVBnVm/btsF1i6KJgx/auexoSCXU1Kk9dJCByh6zK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVBnVm/btsF1i6KJgx/auexoSCXU1Kk9dJCByh6zK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVBnVm%2FbtsF1i6KJgx%2FauexoSCXU1Kk9dJCByh6zK%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;848&quot; height=&quot;630&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;630&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;정적인 클래스 의존관계는 클래스 코드만 봐도 알 수 있는데 실제 어떤 객체가 OrderServiceImpl에 주입될지는 알 수 없다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;메모리 리포지토리에 메모리멤버리포지토리가 들어올지 db메모리리포지토리가 들어올지, 할인정책에 정률 정책이 들어올지 정액 정책이 들어올지 알 수 없다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;동적인 객체 인스턴스 의존관계&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sbRgN/btsF0mhAQpZ/umKjzz8AbgQSt7zhmKBOK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sbRgN/btsF0mhAQpZ/umKjzz8AbgQSt7zhmKBOK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sbRgN/btsF0mhAQpZ/umKjzz8AbgQSt7zhmKBOK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsbRgN%2FbtsF0mhAQpZ%2FumKjzz8AbgQSt7zhmKBOK0%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;847&quot; height=&quot;316&quot; data-origin-width=&quot;847&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;객체다이어그램은 애플리케이션이 실행할때마다 동시에 바뀐다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;정적인 그림은 하나도 손댈 필요없이 동적인 그림만 바꾸면 된다. 정적인 그림에 손을 대지 않는다는 것은 의존관계에 손대지 않는다는 말 =&amp;gt;DI의 장점&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스프링으로 전환하기&lt;/h2&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Configuration
public class AppConfig { //나의 애플리케이션 전체에 대해 설정하고 구성하는 공간

    //멤버서비스에 대한 구현을 나의 애플리케이션에서는 멤버서비스 인플을 쓸거야
    @Bean
    public MemberService memberService() { //AppCofig를 쓸때 멤버서비스 씀
        return new MemberServiceImpl(MemberRepository()); //멤버서비스 구현체인 객체가 생성됨
    }

    //나의 애플리케이션에서는 멤버 리포지토리는 메모리멤버리포지토리로 할거야 -&amp;gt; 나중에 jdbc 리포지토리로 바껴도 이 코드만 바꾸면 된다.
    @Bean
    public MemoryMemberRepository MemberRepository() {
        return new MemoryMemberRepository();
    }

    //오더서비스에 대한 구현을 나의 애플리케이션에서는 오더서비스 인플을 쓸건데 멤버리포지토리는 메모리멤버리포지토리, 디스카운트폴리시는 픽스디스카운트 폴리시 쓸거야
    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(MemberRepository(), discountPolicy()); //AppConfig에서 구현객체를 생성함
    }

    @Bean
    public DiscountPolicy discountPolicy() {
        //return new FixDiscountPolicy();
        //할인클래스를 구체 객체로 바꾸기
        return new RateDiscountPolicy();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;@Configuration 하면 애플리케이션의 설정정보를 나타냄&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;각메소드에 @Bean을 달면 메소드명으로 스프링 컨테이너에 등록하게 됨&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;ApplicationContext : 스프링컨테이너 @Bean 달은 애들을 다 관리&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;AppConfig.class 에 있는 환경 설정 정보를 가지고 스프링이 @Bean 달린 애들을 넣어 관리해줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변경 전(자바)&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class MemberApp {
    public static void main(String[] args) {
//        AppConfig appConfig = new AppConfig(); //이거 무조건 만들어야댐
//        MemberService memberService = appConfig.memberService();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변경 후(스프링)&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class MemberApp {
    public static void main(String[] args) {
//        AppConfig appConfig = new AppConfig(); //이거 무조건 만들어야댐
//        MemberService memberService = appConfig.memberService();
        //MemberService memberService = new MemberServiceImpl();

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean(&quot;memberService&quot;, MemberService.class);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;변경전에는 직접 찾아왔다면 변경후에는 스프링컨테이너를 통해 찾아온다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;AppConfig에서 @Bean이 달린 메소드가 스프링컨테이너에 등록될때 메소드명으로 등록되는데 이걸 getBean 첫번째 파라미터에 적으면 '이 이름으로 이 객체를 찾을거야'라는 뜻이 된다. 두번째는 반환타입이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;public class OrderApp {
    public static void main(String[] args) {
//        AppConfig appConfig = new AppConfig();
//        MemberService memberService = appConfig.memberService();
//        OrderService orderService = appConfig.orderService();
        //MemberService memberService = new MemberServiceImpl();
        //OrderService orderService = new OrderServiceIml();

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean(&quot;memberService&quot;, MemberService.class);
        OrderService orderService = applicationContext.getBean(&quot;orderService&quot;, OrderService.class);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;orderService 꺼내보면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;AppConfig의 orderService에서 리턴한 OrderServiceIml이 나온다&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;@Bean
public OrderService orderService() {
    return new OrderServiceImpl(MemberRepository(), discountPolicy()); //AppConfig에서 구현객체를 생성함
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</description>
      <category>Springboot</category>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/141</guid>
      <comments>https://xandxlass.tistory.com/141#entry141comment</comments>
      <pubDate>Fri, 22 Mar 2024 15:47:30 +0900</pubDate>
    </item>
    <item>
      <title>백준 JAVA 1021 분해합 리뷰</title>
      <link>https://xandxlass.tistory.com/140</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;풀이&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;시간복잡도는 원소 삽입 O(N), indexOf 메서드 사용할때 O(N), 큐 회전 O(N)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;시간 복잡도 O(N^3) N이 최대 50이니까 50*50*50=125000 이다&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;코드&lt;/h2&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;/** 3주차
 * 1.BOJ 1021
 * 2.덱
 * 3.양방향으로 원소를 추가/삭제한다는 점, 끝에 있는 원소들만 추가/삭제하지 중간에 있는 원소들은 건드리지 않는다는점,
 * 덱을 이용했지만 덱의 내장함수로 인덱스를 구할 방법이 없는 것 같아서 링크드리스트 사용함
 * 4.O(N^3)
 */

/** 배운점
 * 1.덱을 STL로 구할거면 Deque&amp;lt;Integer&amp;gt; deque = new LinkedList&amp;lt;&amp;gt;() 만 생각했는데 이번에 내장함수 사용을 위해
 * LinkedList를 사용해서 문제를 푸니 고정된 사고를 벗어날 수 있었다.
 * 2.인덱스를 활용해서 푸는 문제로, 유동적인 부분을 잘 설정했어야했는데 유동적으로 변하는 인덱스, 배열 사이즈에 대한 고려가 좀 부족했다.
 * 유동적으로 변하는 LinkedList의 특징을 기억하면서 변수 설정을 잘 해야겠다.
 */

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        LinkedList&amp;lt;Integer&amp;gt; deque = new LinkedList&amp;lt;Integer&amp;gt;();

        for(int i=1; i&amp;lt;=n; i++){
            deque.add(i);
        }

        int count=0;
        st = new StringTokenizer(br.readLine());

        for(int i=0; i&amp;lt;m; i++){
            int target = Integer.parseInt(st.nextToken());

            while(true) {
                if (deque.getFirst() == target) {
                    deque.removeFirst();
                    break;
                }

                int target_index = deque.indexOf(target);
                int mid = 0;
                if (deque.size() % 2 == 1) { //홀수
                    mid = deque.size() / 2;
                }
                if (deque.size() % 2 == 0) { //짝수
                    mid = (deque.size() / 2)-1;
                }

                if (mid - target_index &amp;gt;= 0) { //mid값보다 왼쪽에 있음 - 2번 실행
                    deque.addLast(deque.removeFirst());
                    count++;
                }

                if (mid - target_index &amp;lt; 0) { //mid값보다 오른쪽에 있음 - 3번 실행
                    deque.addFirst(deque.removeLast());
                    count++;
                }
            }
        }

        System.out.println(count);

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;바킹독 정답 코드 보고 개선한 코드&lt;/h2&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        LinkedList&amp;lt;Integer&amp;gt; deque = new LinkedList&amp;lt;Integer&amp;gt;();

        for(int i=1; i&amp;lt;=n; i++){
            deque.add(i);
        }

        int count=0;
        st = new StringTokenizer(br.readLine());

        for(int i=0; i&amp;lt;m; i++){
            int target = Integer.parseInt(st.nextToken());

            while(deque.getFirst() != target) {
                int target_index = deque.indexOf(target);

                if(target_index&amp;lt;deque.size()-target_index){
                    deque.addLast(deque.removeFirst());

                }else{
                    deque.addFirst(deque.removeLast());

                }
                count++;
            }
            deque.removeFirst();
        }

        System.out.println(count);

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://st-lab.tistory.com/216&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고1&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/encrypted-def/basic-algo-lecture/blob/master/0x07/solutions/1021.cpp&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고2&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@bb222d/%EB%B0%B1%EC%A4%801021%EB%B2%88-%ED%9A%8C%EC%A0%84%ED%95%98%EB%8A%94-%ED%81%90&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;참고3&lt;/a&gt;&lt;/p&gt;</description>
      <category>알고리즘 리뷰</category>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/140</guid>
      <comments>https://xandxlass.tistory.com/140#entry140comment</comments>
      <pubDate>Wed, 20 Mar 2024 20:47:39 +0900</pubDate>
    </item>
    <item>
      <title>[자바/자료구조] 덱 개념 정리</title>
      <link>https://xandxlass.tistory.com/139</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://blog.encrypted.gg/935&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;바킹독 개념&lt;/a&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;877&quot; data-origin-height=&quot;421&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bc7hVR/btsFRjx9zY3/KWoPu2Cl8dDPyJkO8GJKJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bc7hVR/btsFRjx9zY3/KWoPu2Cl8dDPyJkO8GJKJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bc7hVR/btsFRjx9zY3/KWoPu2Cl8dDPyJkO8GJKJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbc7hVR%2FbtsFRjx9zY3%2FKWoPu2Cl8dDPyJkO8GJKJK%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;877&quot; height=&quot;421&quot; data-origin-width=&quot;877&quot; data-origin-height=&quot;421&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;덱은 양쪽 끝에서 삽입과 삭제가 전부 가능하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;어떤 쪽으로 입력하고 어떤 쪽으로 출력하느냐에 따라서 스택(Stack)으로 사용할 수도 있고, 큐(Queue)로도 사용할 수 있다.&lt;/b&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;927&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6uzvm/btsFPa3JdGD/XKokbZnZ894Vrp8Dtaudlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6uzvm/btsFPa3JdGD/XKokbZnZ894Vrp8Dtaudlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6uzvm/btsFPa3JdGD/XKokbZnZ894Vrp8Dtaudlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6uzvm%2FbtsFPa3JdGD%2FXKokbZnZ894Vrp8Dtaudlk%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;927&quot; height=&quot;332&quot; data-origin-width=&quot;927&quot; data-origin-height=&quot;332&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;h2 data-ke-size=&quot;size26&quot;&gt;덱의 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&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;952&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UKtyr/btsFR2Qd5iW/9SkpUXE8xcpPwOQMkCcyyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UKtyr/btsFR2Qd5iW/9SkpUXE8xcpPwOQMkCcyyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UKtyr/btsFR2Qd5iW/9SkpUXE8xcpPwOQMkCcyyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUKtyr%2FbtsFR2Qd5iW%2F9SkpUXE8xcpPwOQMkCcyyk%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;952&quot; height=&quot;412&quot; data-origin-width=&quot;952&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot;&gt;head는 가장 앞에 있는 원소의 인덱스이고 tail을 가장 뒤에 있는 원소의 인덱스 + 1이다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwxzML/btsFPdlXIWH/Y11NVD547pBSX3T60RfxFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwxzML/btsFPdlXIWH/Y11NVD547pBSX3T60RfxFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwxzML/btsFPdlXIWH/Y11NVD547pBSX3T60RfxFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcwxzML%2FbtsFPdlXIWH%2FY11NVD547pBSX3T60RfxFK%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;555&quot; height=&quot;136&quot; data-origin-width=&quot;555&quot; data-origin-height=&quot;136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;덱은 양쪽에서 모두 삽입 가능하기 때문에 양쪽으로 확장해야한다. 시작지점을 0으로 잡으면 왼쪽으로 확장할 수 없게 된다. 시작 지점을 배열의 중간으로 둬야한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;그래서 배열의 크기는 2*MX+1이고 head와 tail의 초기값은 MX이다&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;여기까지가 배열로 덱을 구현하는 방법이었고 STL로 구현하는 방법을 알아보겠다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;JAVA의 덱&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;자바에서의 덱은 인터페이스로 구현되었다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;덱 자료구조의 여러 연산들을 정의한 Deque 인터페이스가 있고 이를 구현한 ArrayDeque, LinkedBlockingDeque, ConcurrentLinkedDeque, LinkedList 등의 클래스가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1710742602226&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Deque&amp;lt;String&amp;gt; deque1 = new ArrayDeque&amp;lt;&amp;gt;();
Deque&amp;lt;String&amp;gt; deque2 = new LinkedBlockingDeque&amp;lt;&amp;gt;();
Deque&amp;lt;String&amp;gt; deque3 = new ConcurrentLinkedDeque&amp;lt;&amp;gt;();
Deque&amp;lt;String&amp;gt; linkedList = new LinkedList&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;Deque 인터페이스의 메소드&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;&amp;lt;삽입&amp;gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yA4zQ/btsFQg3YSt0/0M3E34qk8HLc9phiGa7eT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yA4zQ/btsFQg3YSt0/0M3E34qk8HLc9phiGa7eT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yA4zQ/btsFQg3YSt0/0M3E34qk8HLc9phiGa7eT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyA4zQ%2FbtsFQg3YSt0%2F0M3E34qk8HLc9phiGa7eT1%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;1280&quot; height=&quot;326&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&quot;addfirst&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;addFirst()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 앞쪽에 엘리먼트를 삽입한다. 용량 제한이 있는 덱의 경우, 용량을 초과하면 예외(Exception)가 발생한다&lt;/p&gt;
&lt;h3 id=&quot;offerfirst&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;offerFirst()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 앞쪽에 엘리먼트를 삽입한다. 정상적으로 엘리먼트가 삽입된 경우 true가 리턴되며, 용량 제한에 걸리는 경우 false를 리턴한다.&lt;/p&gt;
&lt;h3 id=&quot;addlast&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;addLast()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 마지막 쪽에 엘리먼트를 삽입한다. 용량 제한이 있는 덱의 경우, 용량 초과시 예외가 발생한다&lt;/p&gt;
&lt;h3 id=&quot;add&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;add()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;addLast()와 동일&lt;/p&gt;
&lt;h3 id=&quot;offerlast&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;offerLast()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 마지막 쪽에 엘리먼트를 삽입한다. 정상적으로 엘리먼트가 삽입된 경우 true가 리턴되며, 용량 제한에 걸리는 경우 false를 리턴한다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;삭제&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;lt;삭제&amp;gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;281&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2aJyf/btsFQN8pqPV/slwUqTKVKkvmZQxkGKvhOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2aJyf/btsFQN8pqPV/slwUqTKVKkvmZQxkGKvhOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2aJyf/btsFQN8pqPV/slwUqTKVKkvmZQxkGKvhOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2aJyf%2FbtsFQN8pqPV%2FslwUqTKVKkvmZQxkGKvhOk%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;1280&quot; height=&quot;281&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;281&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&quot;removefirst&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;removeFirst()&lt;/h2&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 앞쪽에서 엘리먼트 하나를 뽑아서 제거한 다음 해당 엘리먼트를 리턴한다. 덱이 비어있으면 예외가 발생한다.&lt;/p&gt;
&lt;h3 id=&quot;pollfirst&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;pollFirst()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 앞쪽에서 엘리먼트 하나를 뽑아서 제거한 다음 해당 엘리먼트를 리턴한다. 덱이 비어있으면 null 이 리턴된다.&lt;/p&gt;
&lt;h3 id=&quot;removelast&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;removeLast()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 마지막 쪽에서 엘리먼트 하나를 뽑아서 제거한 다음 해당 엘리먼트를 리턴한다. 덱이 비어있으면 예외가 발생한다.&lt;/p&gt;
&lt;h3 id=&quot;polllast&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;pollLast()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 마지막 쪽에서 엘리먼트 하나를 뽑아서 제거한 다음 해당 엘리먼트를 리턴한다. 덱이 비어있으면 null 이 리턴된다.&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;remove()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;removeFirst()와 동일&lt;/p&gt;
&lt;h3 id=&quot;poll&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;poll()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;pollFirst()와 동일&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;값-추출&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;lt;값 추출&amp;gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blBe1v/btsFUqXNjAj/K0OLTlrs6UiobQEpzz0LdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blBe1v/btsFUqXNjAj/K0OLTlrs6UiobQEpzz0LdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blBe1v/btsFUqXNjAj/K0OLTlrs6UiobQEpzz0LdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblBe1v%2FbtsFUqXNjAj%2FK0OLTlrs6UiobQEpzz0LdK%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;1280&quot; height=&quot;292&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&quot;getfirst&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;getFirst()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 앞쪽 엘리먼트 하나를 제거하지 않은채 리턴한다. 덱이 비어있으면 예외가 발생한다&lt;/p&gt;
&lt;h3 id=&quot;peekfirst&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;peekFirst()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 앞쪽 엘리먼트 하나를 제거하지 않은채 리턴한다. 덱이 비어있으면 null이 리턴된다.&lt;/p&gt;
&lt;h3 id=&quot;getlast&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;getLast()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 마지막쪽 엘리먼트 하나를 제거하지 않은채 리턴한다. 덱이 비어있으면 예외가 발생한다.&lt;/p&gt;
&lt;h3 id=&quot;peeklast&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;peekLast()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 마지막 엘리먼트 하나를 제거하지 않은 채 리턴한다. 덱이 비어있으면 null이 리턴된다.&lt;/p&gt;
&lt;h3 id=&quot;peek&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;peek()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;peekFirst()와 동일&lt;/p&gt;
&lt;h3 id=&quot;그-외&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;lt;그 외&amp;gt;&lt;/h3&gt;
&lt;h3 id=&quot;removefirstoccurrenceobject-o&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;removeFirstOccurrence(Object o)&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 앞쪽에서부터 탐색하여 입력한 Object o와 동일한 첫 엘리먼트를 제거한다. Object o 와 같은 엘리먼트가 없으면 덱에 변경이 발생하지 않는다.&lt;/p&gt;
&lt;h3 id=&quot;removelastoccurrenceobject-o&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;removeLastOccurrence(Object o)&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱의 뒤쪽에서부터 탐색하여 입력한 Object o와 동일한 첫 엘리먼트를 제거한다. Object o 와 같은 엘리먼트가 없으면 덱에 변경이 발생하지 않는다.&lt;/p&gt;
&lt;h3 id=&quot;element&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;element()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;removeFirst()와 동일&lt;/p&gt;
&lt;h3 id=&quot;push&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;push()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;addFirst()와 동일. 덱을 스택으로 사용할 때 쓰임&lt;/p&gt;
&lt;h3 id=&quot;pop&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;pop()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;removeFirst()와 동일. 덱을 스택으로 사용할 때 쓰임&lt;/p&gt;
&lt;h3 id=&quot;removeobject-o&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;remove(Object o)&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;removeFirstOccurrence(Object o)와 동일&lt;/p&gt;
&lt;h3 id=&quot;containobject-o&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;contain(Object o)&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;덱에 Object o와 동일한 엘리먼트가 포함되어 있는지 확인&lt;/p&gt;
&lt;h3 id=&quot;size&quot; style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;size()&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;Deque에 들어있는 엘리먼트의 개수&lt;/p&gt;</description>
      <category>알고리즘 리뷰</category>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/139</guid>
      <comments>https://xandxlass.tistory.com/139#entry139comment</comments>
      <pubDate>Mon, 18 Mar 2024 16:10:19 +0900</pubDate>
    </item>
    <item>
      <title>스프링 핵심 원리-기본편 섹션 2. 스프링 핵심 원리 이해1 정리</title>
      <link>https://xandxlass.tistory.com/138</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;비지니스 요구사항과 설계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;853&quot; data-origin-height=&quot;292&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJpULM/btsFPcmu8HX/8EvZX9qn63CK1sODAjwdbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJpULM/btsFPcmu8HX/8EvZX9qn63CK1sODAjwdbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJpULM/btsFPcmu8HX/8EvZX9qn63CK1sODAjwdbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJpULM%2FbtsFPcmu8HX%2F8EvZX9qn63CK1sODAjwdbk%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;853&quot; height=&quot;292&quot; data-origin-width=&quot;853&quot; data-origin-height=&quot;292&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L4YTb/btsFRsBbYAR/2zmkxp0gnqBnHI0F31eoo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L4YTb/btsFRsBbYAR/2zmkxp0gnqBnHI0F31eoo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L4YTb/btsFRsBbYAR/2zmkxp0gnqBnHI0F31eoo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL4YTb%2FbtsFRsBbYAR%2F2zmkxp0gnqBnHI0F31eoo1%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;885&quot; height=&quot;592&quot; data-origin-width=&quot;885&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;회원 도메인 협력 관계 &lt;/b&gt;:&amp;nbsp;기획자들도&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;회원클래스다이어그램&lt;/b&gt; (정적): 회원 도메인 협력 관계를 분석해서 만든것&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;회원 클래스 다이어그램은 서버를 실행하지 않고 클래스들만 분석해서 볼 수 있는 그림&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;db 구현체를 넣을지 외부 구현체를 넣을지 결정하는건 동적으로 결정하기 때문에 클래스다이어그램으로 판단하기 어려움&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;그래서&lt;b&gt; 객체 다이어그램&lt;/b&gt;(동적)을 만든다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;빌드하면 main에 대한 코드만 나가고 test 코드는 빌드될때 빠진다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;회원 도메인 실행과 테스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;순수 자바 코드로 테스트하기&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class MemberApp {
    public static void main(String[] args) {
        MemberService memberService = new MemberServiceImpl();
        Member member = new Member(1L, &quot;memberA&quot;, Grade.VIP);
        memberService.join(member);

        Member findMember = memberService.findMember(1L);
        System.out.println(&quot;findMember = &quot; + member.getName());
        System.out.println(&quot;findMember = &quot; + findMember.getName());

    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;MemberServiceTest&amp;nbsp; Junit으로 테스트&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;public class MemberServiceTest {
    MemberService memberService = new MemberServiceImpl();
    @Test
    void join() {
        //given : 이런 환경이 주어졌을때
        Member member = new Member(1L, &quot;memberA&quot;, Grade.VIP);

        //when : 이렇게 했을때
        memberService.join(member);
        Member findMember = memberService.findMember(1L);

        //then : 이렇게 된다
        Assertions.assertThat(member).isEqualTo(findMember);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class MemberServiceImpl implements MemberService{
    private final MemberRepository memberRepository = new MemoryMemberRepository();
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;이 코드의 문제는 멤버서비스가 멤버리포지토리(인터페이스)에도 의존하고 메모리멤버리포지토리(구현체)에도 의존하고 있다. DIP 위반&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; 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;852&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q45Rs/btsFPoAbfYm/KUzlhtPSeg16sZdGKJOVg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q45Rs/btsFPoAbfYm/KUzlhtPSeg16sZdGKJOVg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q45Rs/btsFPoAbfYm/KUzlhtPSeg16sZdGKJOVg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ45Rs%2FbtsFPoAbfYm%2FKUzlhtPSeg16sZdGKJOVg0%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;852&quot; height=&quot;283&quot; data-origin-width=&quot;852&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;회원을 메모리에서 조회하고, 정액 할인 정책(고정 금액)을 지원해도 주문 서비스를 변경하지 않아도 된다. 역할들의 협력 관계를 그대로 재사용 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉 메모리회원 저장소를 db멤버리포지토리로 바꿔도, 정액 할인정책을 정률할인정책으로 바꿔도 주문 서비스 구현체가 바뀌지 않는다&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주문과 할인 도메인 개발&lt;/h2&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class OrderServiceIml implements OrderService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();
    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);
        
        return new Order(memberId, itemName, itemPrice, discountPrice); //최종 생성된 주문 반환
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;createOrder를 보면 멤버 가져오고 나서 discountPolicy 한테 멤버랑 아이템 가격 보낼테니 알아서 하고 결과만 던져달라고 하는 코드인데 단일책임원칙을 잘 지킨 코드다.&lt;/p&gt;</description>
      <category>Springboot</category>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/138</guid>
      <comments>https://xandxlass.tistory.com/138#entry138comment</comments>
      <pubDate>Fri, 15 Mar 2024 22:33:56 +0900</pubDate>
    </item>
    <item>
      <title>스프링 핵심 원리-기본편 섹션 1. 객체 지향 설계와 스프링 정리</title>
      <link>https://xandxlass.tistory.com/137</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;좋은 객체지향 설계의 5가지 원칙(SOLID)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SRP 단일 책임 원칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;한 클래스는 하나의 책임만 가져야한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;중요한건 &lt;b&gt;변경&lt;/b&gt;이다. 변경이 있을때 파급효과가 적으면 단일 책임 원칙을 잘 따른것&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;OCP 개방-폐쇄 원칙&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;소프트웨어 요소는 &lt;b&gt;확장&lt;/b&gt;에는&lt;b&gt; 열려&lt;/b&gt; 있으나 &lt;b&gt;변경&lt;/b&gt;에는 &lt;b&gt;닫혀&lt;/b&gt; 있어야한다 =&amp;gt; &lt;b&gt;다형성&lt;/b&gt; 활용&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;아래는 멤버서비스에서 메모리멤버리포지토리를 Jdbc 멤버리포지토리로 갈아끼우려고 하는 상황이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2cpqF/btsFQzA7pHH/4lteKkpg9pudk3RRd3Y5Nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2cpqF/btsFQzA7pHH/4lteKkpg9pudk3RRd3Y5Nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2cpqF/btsFQzA7pHH/4lteKkpg9pudk3RRd3Y5Nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2cpqF%2FbtsFQzA7pHH%2F4lteKkpg9pudk3RRd3Y5Nk%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;791&quot; height=&quot;311&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;두번째 코드를 보면 다형성만 사용하면 OCP 원칙을 지킬 수 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;구현 객체를 변경하려면 클라이언트 코드를 변경해야하는 문제가 생긴다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LSP 리스코프 치환 원칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;차를 만든다고 했을때 인터페이스에서 엑셀 기능을 속도를 올리는 것으로 규정을 했다면 구현체에서 엑셀을 속도 마이너스 10 이런식으로 구현할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ISP 인터페이스 분리 원칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;적절하게 인터페이스를 나누는 것이 좋다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;DIP 의존관계 역전 원칙&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;멤버서비스가 메모리 리포지토리 인터페이스만 바라보고 메모리멤버 리포지토리나 JDBC 멤버 리포지토리에 대해서는 몰라야한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pHjVL/btsFRBStFVs/hThQxJQ6UzKlqBI7aFyOCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pHjVL/btsFRBStFVs/hThQxJQ6UzKlqBI7aFyOCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pHjVL/btsFRBStFVs/hThQxJQ6UzKlqBI7aFyOCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpHjVL%2FbtsFRBStFVs%2FhThQxJQ6UzKlqBI7aFyOCK%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;688&quot; height=&quot;337&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;337&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;그림으로 설명하자면 운전자가 자동차 역할에 대해 알고 있어야지 K3에 대해 잘 알고 있으면 안된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;역할과 구현을 철저하게 분리하고 시스템을 언제든지 갈아끼울 수 있게 설계&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2cpqF/btsFQzA7pHH/4lteKkpg9pudk3RRd3Y5Nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2cpqF/btsFQzA7pHH/4lteKkpg9pudk3RRd3Y5Nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2cpqF/btsFQzA7pHH/4lteKkpg9pudk3RRd3Y5Nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2cpqF%2FbtsFQzA7pHH%2F4lteKkpg9pudk3RRd3Y5Nk%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;791&quot; height=&quot;311&quot; data-origin-width=&quot;791&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;위의 코드 문제점: 멤버서비스 new 를 보면 메모리 멤버 리포지토리에도 의존하고 있다. 의존한다는건 저 코드를 안다는 뜻&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;즉 멤버서비스는 메모리리포지토리와 메모리멤버리포지토리를 안다는 뜻이다. 그래서 메모리 멤버리포지토리를 변경하려고 할 때 아래와 같이 코드를 변경해야하는 문제가 발생한다 (DIP 위반)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;객체 지향 설계와 스프링&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;인페이스를 모두 도입하면 좋지만 추상화라는 비용이 발생한다. 코드를 인터페이스를 열고 구현체들도 열고 이래야하는 단점이 있음&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;미래에 기능을 확장할 가능성이 있다 : 처음부터 인터페이스 만들기&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;미래에 기능을 확장할 가능성이 없다 : 구체 클래스를 직접 사용하고 향후 꼭 필요할때 리팩터링해서 인터페이스 도입&lt;/p&gt;</description>
      <category>Springboot</category>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/137</guid>
      <comments>https://xandxlass.tistory.com/137#entry137comment</comments>
      <pubDate>Fri, 15 Mar 2024 21:14:32 +0900</pubDate>
    </item>
    <item>
      <title>큐 개념 정리 JAVA</title>
      <link>https://xandxlass.tistory.com/136</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=D_fwSy5tRAY&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;바킹독강의&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;큐 정의&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;한쪽 끝에서 원소를 넣고 한쪽 끝에서 원소를 뺄 수 있는 자료구조&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;먼저 들어온 원소가 먼저 나오게 된다 FIFO&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&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;895&quot; data-origin-height=&quot;295&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5EMPY/btsFOFOC2RM/T23RKelfhyqKNgyZ9nz9Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5EMPY/btsFOFOC2RM/T23RKelfhyqKNgyZ9nz9Rk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5EMPY/btsFOFOC2RM/T23RKelfhyqKNgyZ9nz9Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5EMPY%2FbtsFOFOC2RM%2FT23RKelfhyqKNgyZ9nz9Rk%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;895&quot; height=&quot;295&quot; data-origin-width=&quot;895&quot; data-origin-height=&quot;295&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4번은 원칙적으로 불가능하지만 배열로 만들면 구현은 가능하다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;큐는 배열로 구현하면 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&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;960&quot; data-origin-height=&quot;407&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdKQnc/btsFNxqeAOK/6dh5KVjUrHGnxUKSojtb6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdKQnc/btsFNxqeAOK/6dh5KVjUrHGnxUKSojtb6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdKQnc/btsFNxqeAOK/6dh5KVjUrHGnxUKSojtb6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdKQnc%2FbtsFNxqeAOK%2F6dh5KVjUrHGnxUKSojtb6K%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;960&quot; height=&quot;407&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;407&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;원소를 넣으면 tail이 한 칸 올라감&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;55 원소를 뺀다고 하면 head를 한 칸 올리면 된다. 굳이 0번지에 있는 55를 덮을 필요 없다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot;&gt;배열에서 dat[head]부터 dat[tail-1]번지가 바로 큐의 원소들이 들어있는 자리&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: justify;&quot;&gt;큐의 크기는 tail - head&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;push 하면 tail이 증가하고 pop하면 head가 증가된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;160&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bX9Q2U/btsFMPkDb28/KxlQ7ctIlLMtMqVdQLYgeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bX9Q2U/btsFMPkDb28/KxlQ7ctIlLMtMqVdQLYgeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bX9Q2U/btsFMPkDb28/KxlQ7ctIlLMtMqVdQLYgeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbX9Q2U%2FbtsFMPkDb28%2FKxlQ7ctIlLMtMqVdQLYgeK%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;547&quot; height=&quot;160&quot; data-origin-width=&quot;547&quot; data-origin-height=&quot;160&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;큐를 삽입 삭제하게 되면 점점 오른쪽으로 밀려나가게 된다. 그러면 배열이니 앞의 공간을 못쓰게 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;437&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bruYAk/btsFPeXzWzZ/EAq6Q0ftKqzF9igI2QWP4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bruYAk/btsFPeXzWzZ/EAq6Q0ftKqzF9igI2QWP4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bruYAk/btsFPeXzWzZ/EAq6Q0ftKqzF9igI2QWP4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbruYAk%2FbtsFPeXzWzZ%2FEAq6Q0ftKqzF9igI2QWP4K%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;437&quot; height=&quot;267&quot; data-origin-width=&quot;437&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;head나 tail에 1이 더해질때 0번지로 다시 오도록 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다른 방법: 배열의 크기를 push의 최대수로 하면 된다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;push 함수&lt;/h2&gt;
&lt;pre id=&quot;code_1710463986006&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void push(int x){
	 dat[tail++]=x
}&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;h2 data-ke-size=&quot;size26&quot;&gt;pop함수&lt;/h2&gt;
&lt;pre id=&quot;code_1710464028734&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void pop(){
	 head++;
}&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;h2 data-ke-size=&quot;size26&quot;&gt;front함수/back 함수&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;pre id=&quot;code_1710464159871&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int front(){
	return dat[head];
}

int back(){
	return dat[tail-1];
}&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;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;큐가 비어있을때 front/back, pop을 호출하면 런타임에러가 발생할 수 있다&lt;/p&gt;</description>
      <category>알고리즘 리뷰</category>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/136</guid>
      <comments>https://xandxlass.tistory.com/136#entry136comment</comments>
      <pubDate>Fri, 15 Mar 2024 10:51:22 +0900</pubDate>
    </item>
    <item>
      <title>자바 Stack 스택 개념 정리</title>
      <link>https://xandxlass.tistory.com/135</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=0DsyCXIN7Wg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;바킹독 스택 개념&lt;/a&gt;을 보고 정리한 글입니다&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스택&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스택은 먼저 들어간 애가 나중에 나오는 구조다 FILO 구조&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스택의 성질&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1.원소의 추가가 O(1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2.원소의 제거가 O(1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3.제일 상단의 원소 확인이 O(1)&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;4.제일 상단이 아닌 나머지 원소들의 확인/변경이 원칙적으로 불가&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스택 구현&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;배열, 연결리스트로 구현 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;223&quot; data-origin-height=&quot;392&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmwwyu/btsFGJkxijY/0QONmnFPFrBKkVYvXvpNx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmwwyu/btsFGJkxijY/0QONmnFPFrBKkVYvXvpNx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmwwyu/btsFGJkxijY/0QONmnFPFrBKkVYvXvpNx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcmwwyu%2FbtsFGJkxijY%2F0QONmnFPFrBKkVYvXvpNx1%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;223&quot; height=&quot;392&quot; data-origin-width=&quot;223&quot; data-origin-height=&quot;392&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스택을 배열로 구현할 때는 원소를 담은 큰 배열 한 개와 인덱스를 저장할 변수 한 개만 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;pos 값이 스택의 길이, 즉 스택 내의 원소의 수를 의미함&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;push 함수&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;442&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIz7Rn/btsFJ7RY8j1/XRJ6MKppEC0jU1uMdmQdr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIz7Rn/btsFJ7RY8j1/XRJ6MKppEC0jU1uMdmQdr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIz7Rn/btsFJ7RY8j1/XRJ6MKppEC0jU1uMdmQdr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIz7Rn%2FbtsFJ7RY8j1%2FXRJ6MKppEC0jU1uMdmQdr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;715&quot; height=&quot;442&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;442&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;pos 값 +1 증가&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;pop 함수&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;435&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCiPAy/btsFGS249GO/kUh6VGgooUevuLfv0cMwF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCiPAy/btsFGS249GO/kUh6VGgooUevuLfv0cMwF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCiPAy/btsFGS249GO/kUh6VGgooUevuLfv0cMwF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCiPAy%2FbtsFGS249GO%2FkUh6VGgooUevuLfv0cMwF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;715&quot; height=&quot;435&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;435&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;pos값만 1 줄이면 된다. 나중에 원소를 넣는다면 arr[pos]에 원소가 들어가면서 알아서 값이 바뀐다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;top 함수&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o3oka/btsFGJdNWHQ/4SzI6CQRAeC1K5GnW9pJFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o3oka/btsFGJdNWHQ/4SzI6CQRAeC1K5GnW9pJFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o3oka/btsFGJdNWHQ/4SzI6CQRAeC1K5GnW9pJFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo3oka%2FbtsFGJdNWHQ%2F4SzI6CQRAeC1K5GnW9pJFK%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;662&quot; height=&quot;400&quot; data-origin-width=&quot;662&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;제일 위의 원소를 확인하는 top 함수다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;STL stack을 쓸 수 있으면 쓰는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;런타임 에러 발생 -&amp;gt; 스택이 비어있는데 top이나 pop을 하진 않았는지 의심해볼 것&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스택 기본 선언&lt;/h2&gt;
&lt;pre id=&quot;code_1710243419848&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Stack&amp;lt;Integer&amp;gt; stack = new Stack&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스택 메서드 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;push(T t)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;데이터를 스택에 추가하고, 해당 값을 반환&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #555555;&quot;&gt;peek()&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스택의 마지막 요소를 반환, 스택에는 영향 X&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스택이 비어있는데 peek() 메서드 호출시 &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;NoSuchElementException 예외가 발생&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;pop()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스택의 마지막 요소를 제거함과 동시에 해당 값 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;empty()&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스택이 비어있는지의 여부를 반환, 비어있을 경우 true, 비어있지 않을 경우 false 반환&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;a href=&quot;https://ittrue.tistory.com/200&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;출처&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘 리뷰</category>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/135</guid>
      <comments>https://xandxlass.tistory.com/135#entry135comment</comments>
      <pubDate>Tue, 12 Mar 2024 20:42:20 +0900</pubDate>
    </item>
    <item>
      <title>김영한 스프링 입문 섹션 7. AOP 정리</title>
      <link>https://xandxlass.tistory.com/134</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;AOP가 필요한 상황&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;453&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r8jBY/btsFHt79C6e/NJdEwVpVop53E59PsdWn10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r8jBY/btsFHt79C6e/NJdEwVpVop53E59PsdWn10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r8jBY/btsFHt79C6e/NJdEwVpVop53E59PsdWn10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr8jBY%2FbtsFHt79C6e%2FNJdEwVpVop53E59PsdWn10%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;857&quot; height=&quot;453&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;453&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;모든 메소드의 호출 시간을 측정하고 싶다고 해서 메소드에 다 추가해버리면 다음과 같은 문제 생긴다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;1.핵심 관심사항이 아니다&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;2.공통 관심사항이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;3.시간 측정 로직과 비지니스 로직이 섞여 유지보수가 어렵다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;4.시간을 측정하는 로직을 별도의 공통 로직으로 만들기 어렵다.&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;850&quot; data-origin-height=&quot;452&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cze50a/btsFEvzBxXm/2EUYSLwcjdHvEd4fESi9EK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cze50a/btsFEvzBxXm/2EUYSLwcjdHvEd4fESi9EK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cze50a/btsFEvzBxXm/2EUYSLwcjdHvEd4fESi9EK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcze50a%2FbtsFEvzBxXm%2F2EUYSLwcjdHvEd4fESi9EK%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;850&quot; height=&quot;452&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;452&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;해결 방법 : AOP 적용하기&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;공통 관심 사항과 핵심 관심사항을 분리하고 원하는 곳에 공통 관심사항을 적용하면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L7R0G/btsFEgiDpeS/ecr9vHxuOZYKOr6AyAzab0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L7R0G/btsFEgiDpeS/ecr9vHxuOZYKOr6AyAzab0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L7R0G/btsFEgiDpeS/ecr9vHxuOZYKOr6AyAzab0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL7R0G%2FbtsFEgiDpeS%2Fecr9vHxuOZYKOr6AyAzab0%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;851&quot; height=&quot;538&quot; data-origin-width=&quot;851&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;기존 의존 관계&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dq5Smv/btsFFmvRRvo/dcIyw0x6lhpHh4vwcN7Ylk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dq5Smv/btsFFmvRRvo/dcIyw0x6lhpHh4vwcN7Ylk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dq5Smv/btsFFmvRRvo/dcIyw0x6lhpHh4vwcN7Ylk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdq5Smv%2FbtsFFmvRRvo%2FdcIyw0x6lhpHh4vwcN7Ylk%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;861&quot; height=&quot;522&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;가짜 멤버 서비스를 만들어서 시간 측정을 하고 joinPoint.proceed()를 통해서 실제 멤버 서비스를 실행한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;866&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LlwCF/btsFGC5Anox/ySK0tkpSsxYkseTf4RY170/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LlwCF/btsFGC5Anox/ySK0tkpSsxYkseTf4RY170/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LlwCF/btsFGC5Anox/ySK0tkpSsxYkseTf4RY170/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLlwCF%2FbtsFGC5Anox%2FySK0tkpSsxYkseTf4RY170%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;866&quot; height=&quot;476&quot; data-origin-width=&quot;866&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;AOP 적용 후 전체 그림은 이렇게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;913&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDWErj/btsFGn1CM8R/q4RxSWPpF7kJSFzGEVWifK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDWErj/btsFGn1CM8R/q4RxSWPpF7kJSFzGEVWifK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDWErj/btsFGn1CM8R/q4RxSWPpF7kJSFzGEVWifK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDWErj%2FbtsFGn1CM8R%2Fq4RxSWPpF7kJSFzGEVWifK%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;913&quot; height=&quot;268&quot; data-origin-width=&quot;913&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;실제로 Proxy가 주입되는지 콘솔에 출력해보면 아래처럼 가짜 멤버서비스가 만들어짐을 알 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;AOP를 스프링빈에 등록할 때 컴포넌트 스캔과 SpringConfig에 직접 등록하는 방법이 있는 데 실무에서는 후자를 선호한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1710046922871&quot; class=&quot;less&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Aspect
@Component
public class TimeTraceAop {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;이렇게 컴포넌트 스캔을 해도 되지만 선호하는 방법은 아래와 같다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1710046922875&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Configuration
public class SpringConfig {
	@Bean
    public TimeTraceAop timeTraceAop(){
        return new TimeTraceAop();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;@Service @Repository 같은건 정형화되어있는데 AOP의 경우 정형화되어있기보단 이거 AOP네 딱 하고 인지하는게 더 좋기 때문에 직접 등록한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;SpringConfig 보고 AOP 존재를 알아채도록 하는게 좋다&lt;/p&gt;</description>
      <category>Springboot</category>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/134</guid>
      <comments>https://xandxlass.tistory.com/134#entry134comment</comments>
      <pubDate>Sun, 10 Mar 2024 14:02:09 +0900</pubDate>
    </item>
    <item>
      <title>김영한 스프링 입문 섹션 6.스프링 DB 접근 기술 정리</title>
      <link>https://xandxlass.tistory.com/133</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;H2 데이터베이스 설치&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;sql문&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1709897916673&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;generated by default as identity&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;null&amp;nbsp;값이&amp;nbsp;들어오면&amp;nbsp;자동으로&amp;nbsp;id&amp;nbsp;세팅해줌&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&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;화면 캡처 2024-03-08 174230.png&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;215&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz97m7/btsFFR3aLvX/hPJLjsBdx3uWPKdWa280Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz97m7/btsFFR3aLvX/hPJLjsBdx3uWPKdWa280Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz97m7/btsFFR3aLvX/hPJLjsBdx3uWPKdWa280Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz97m7%2FbtsFFR3aLvX%2FhPJLjsBdx3uWPKdWa280Ck%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;835&quot; height=&quot;215&quot; data-filename=&quot;화면 캡처 2024-03-08 174230.png&quot; data-origin-width=&quot;835&quot; data-origin-height=&quot;215&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;팁:sql&amp;nbsp;ddl을&amp;nbsp;sql&amp;nbsp;파일을&amp;nbsp;만들어&amp;nbsp;관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;순수 JDBC&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;자바가 DB랑 붙으려면 JDBC가 꼭 있어야한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이번 강의에서는 과거에 사용하던 방식으로 구현을 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;JdbcMemberRepository&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class JdbcMemberRepository implements MemberRepository {

    private final DataSource dataSource;

    public JdbcMemberRepository(DataSource dataSource) {
        this.dataSource = dataSource;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스프링부트가&amp;nbsp;데이터소스(접속정보)를&amp;nbsp;만들고&amp;nbsp;데이터소스를&amp;nbsp;주입받는다. &lt;br /&gt;진짜&amp;nbsp;데이터베이스랑&amp;nbsp;연결된&amp;nbsp;정보를&amp;nbsp;얻을&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이번 강의에서 제일 중요한 점은 JdbcMemberRepository 코드가 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;SpringConfig 가 핵심이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;SpringConfig&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Configuration
public class SpringConfig {
    //JdbcMemberRepository는 dataSource가 필요하다 이건 스프링이 제공해준다
    //스프링부트가 프로퍼티즈 보고 자체적으로 dataSource 만들고 DI 해준다.
    private final DataSource dataSource;

    @Autowired
    public SpringConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean //스프링빈 등록할거야
    public MemberService memberService(){
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository(){

        //return new MemoryMemberRepository(); //인터페이스는 new 안됨
        return new JdbcMemberRepository(dataSource);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;강의 초반에 비지니스 요구사항에서 DB가 정해지지 않아서 인터페이스와 구현체를 만들고 나중에 다른 리포지토리로 바꾸려고 계획을 했었다. 이를 가능하게 만드는 것이 스프링의 장점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;JdbcMemberRepository&lt;span&gt; 와 SpringConfig 파일을 제외하고 어떤 코드도 손대지 않았다. 이 두 파일만 손대니 구현체를 바꿔끼울 수 있었다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coQd8q/btsFGk4Tewq/zlgRX6BMkSFWzyx1Fqc0p0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coQd8q/btsFGk4Tewq/zlgRX6BMkSFWzyx1Fqc0p0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coQd8q/btsFGk4Tewq/zlgRX6BMkSFWzyx1Fqc0p0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoQd8q%2FbtsFGk4Tewq%2FzlgRX6BMkSFWzyx1Fqc0p0%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;880&quot; height=&quot;480&quot; data-origin-width=&quot;880&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;567&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ejCQF9/btsFExxa02N/TjtRO2dV1DgLAKBTKyG3Kk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ejCQF9/btsFExxa02N/TjtRO2dV1DgLAKBTKyG3Kk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ejCQF9/btsFExxa02N/TjtRO2dV1DgLAKBTKyG3Kk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FejCQF9%2FbtsFExxa02N%2FTjtRO2dV1DgLAKBTKyG3Kk%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;861&quot; height=&quot;567&quot; data-origin-width=&quot;861&quot; data-origin-height=&quot;567&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;size18&quot;&gt;가장 중요한 개방 폐쇄 원칙(OCP) (확장에는 열려있고 수정, 변경에는 닫혀있다)를 지킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스프링의 DI를 사용하면 기존 코드를 전혀 손대지 않고 설정만으로 구현클래스를 변경할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스프링 통합 테스트&lt;/h2&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@SpringBootTest
class MemberServiceIntegrationTest {
    //스프링한테 멤버서비스, 멤버리포지토리 내놔 해야됨
    //어떻게? DI 하기 근데 테스트는 끝단에 있는거라 편한 방법 사용함 @Autowired 사용
    @Autowired MemberService memberService;
    @Autowired MemberRepository memberRepository; //구현체는 SpringConfig에서 올라올거임

    @Test
    void 회원가입() { //테스트는 한글로 해도 상관무
        //given
        Member member = new Member();
        member.setName(&quot;spring1&quot;);

        //when 
        Long saveId = memberService.join(member);

        //then
        Member findMember=memberService.findOne(saveId).get();
        assertThat(member.getName()).isEqualTo(findMember.getName());
    }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1709900619963&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Autowired MemberService memberService;
@Autowired MemberRepository memberRepository; //구현체는 SpringConfig에서 올라올거임&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;size18&quot;&gt;스프링한테 멤버서비스, 멤버리포지토리 내놔 해야됨 &lt;br /&gt;어떻게? DI 하기 근데 테스트는 끝단에 있는거라 편한 방법 사용함 @Autowired 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;구현체는 SpringConfig에서 올라오니까 인터페이스를 연결&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이 상태로 테스트를 하면 에러가 난다. DB에 앞서 했던 데이터들이 저장되어있기 때문에 이미 존재하는 회원이라는 에러가 뜬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이미&amp;nbsp;존재하는&amp;nbsp;회원이라는&amp;nbsp;에러-&amp;gt;db&amp;nbsp;삭제 &lt;br /&gt;실제로는 운영 db를 지우는게 아니라 테스트 디비 or 로컬 pc 디비를 돌려서 확인함&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;br /&gt;다시 실행하면 테스트는 통과되지만 다시 또 하면 에러가 난다. DB에 저장되어있기 때문&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;테스트는 여러번 계속 반복할 수 있어야한다! =&amp;gt; @Transactional 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;해결방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;DB는 트랜잭션이라는 개념이 있다. 커밋을 해야 DB에 반영이 된다. 커밋 하기 전까지는 반영이 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;테스트 끝난 후에 롤백하면 DB 데이터가 다 날라간다 그래서 롤백해주는 어노테이션을 달면 해결이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;@Transactional 을 달면 트랜잭션 후에 DB 쿼리를 다 하고 테스트 끝나면 롤백을 해준다. 그러면 DB 데이터가 반영이 안된다. 이 기능은 테스트에서만 적용됨&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;순수한 자바로만 하는 테스트:단위테스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스프링컨테이너+DB까지 불러서 하는 테스트 :통합테스트&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;단위테스트가 훨씬 좋은 테스트다 계속 연습하는 게 중요&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스프링 JdbcTemplate&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;람다식 변경 단축키 알트+엔터&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;마지막으로 실행했던 걸 다시 실행 단축키: 컨트롤+R&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;JdbcTemplate는 JDBC API에서 본 반복 코드를 대부분 제거해준다. 하지만 SQL은 직접 작성해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;JdbcMemberRepository의 코드와 JdbcTemplate를 활용해 만든 JdbcTemplateMemberRepository 파일을 비교해보면 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;JdbcTemplateMemberRepository&lt;span&gt; 가&amp;nbsp;&lt;/span&gt;&lt;/span&gt;코드 단축이 엄청 됐다는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이번 강의에서는 JdbcTemplate를 활용해서 코드 단축을 하고 SpringConfig에 구현체를&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;JdbcTemplateMemberRepository&lt;span&gt; 로 바꾸는 실습을 했다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;JPA&lt;/span&gt;&lt;/h2&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Entity
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;DB 쿼리에 insert into values~ 할때 name을 넣지, id는 넣지 않는다. id를 넣지 않아도 DB에서 자동으로 생성 해주는데 이러한 것을 IDENTITY 전략이라고 한다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;spring.jpa.show-sql=true&amp;nbsp;//Jpa가&amp;nbsp;날리는&amp;nbsp;sql을&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있다 &lt;br /&gt;spring.jpa.hibernate.ddl-auto=none&amp;nbsp;//jpa가&amp;nbsp;객체를&amp;nbsp;보고&amp;nbsp;테이블을&amp;nbsp;만들어줌&amp;nbsp;근데&amp;nbsp;우린&amp;nbsp;이미&amp;nbsp;만들었으니까&amp;nbsp;끔&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Override
public List&amp;lt;Member&amp;gt; findAll() {
    List&amp;lt;Member&amp;gt; result = em.createQuery(&quot;select m from Member m&quot;, Member.class)
            .getResultList();
    return result;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;result 로 받고 result를 return 함 똑같으면 인라인 해주면 좋다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;단축키:컨트롤+알트+N&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Override
public List&amp;lt;Member&amp;gt; findAll() {
    return em.createQuery(&quot;select m from Member m&quot;, Member.class)
            .getResultList();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;select m from Member m 이 JPQL 쿼리문이다. 객체를 대상으로 쿼리를 날리는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;select m&lt;span&gt; 객체 자체를 select 한게 포인트&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;PK 기반이 아닌 것들은 JPQL을 써야한다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;JPA를 쓰려면 항상 트랜잭션이 있어야한다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;JPA는 트랜잭션 안에서 다 실행되어야 한다&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;스프링 데이터 JPA&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;div style=&quot;background-color: #ffffff; color: #080808;&quot;&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;public interface SpringDataJpaMemberRepository extends JpaRepository&amp;lt;Member, Long&amp;gt;, MemberRepository {
    @Override
    Optional&amp;lt;Member&amp;gt; findByName(String name);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;스프링데이터 JPA가 JpaRepository가 있으면 구현체를 자동으로 만들고 등록해준다. 그걸 그대로 가져다쓴다&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;스프링 데이터 JPA 제공 기능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1.인터페이스를 통한 기본적인 CRUD&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2.findByName(), findByEmail() 처럼 메서드 이름 만으로 조회 기능 제공&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;3. 페이징 기능 자동 제공&lt;/p&gt;</description>
      <category>Springboot</category>
      <author>xandxlass</author>
      <guid isPermaLink="true">https://xandxlass.tistory.com/133</guid>
      <comments>https://xandxlass.tistory.com/133#entry133comment</comments>
      <pubDate>Sat, 9 Mar 2024 20:58:58 +0900</pubDate>
    </item>
  </channel>
</rss>