<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>gudals-kim.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Wed, 09 Aug 2023 04:49:49 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>gudals-kim.log</title>
            <url>https://velog.velcdn.com/images/gudals-kim/profile/70e35920-3c74-4ef3-80ff-a7738b259144/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. gudals-kim.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/gudals-kim" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[싱글톤 컨테이너]]></title>
            <link>https://velog.io/@gudals-kim/4.-%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</link>
            <guid>https://velog.io/@gudals-kim/4.-%EC%8B%B1%EA%B8%80%ED%86%A4-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88</guid>
            <pubDate>Wed, 09 Aug 2023 04:49:49 GMT</pubDate>
            <description><![CDATA[<h1 id="🍃-싱글톤-컨테이너">🍃 싱글톤 컨테이너</h1>
<blockquote>
<p><code>스프링 컨터이너</code>는 객체 인스턴스를 싱글톤으로 관리하기 때문에 <strong>싱글톤 컨테이너 역할</strong>을 한다.</p>
</blockquote>
<hr>
<h2 id="1-싱글톤-패턴">1. 싱글톤 패턴</h2>
<blockquote>
<p>클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴</p>
</blockquote>
<hr>
<pre><code class="language-java">public class SingletonService {
    //1. static 영역에 객체를 딱 1개만 생성해둔다.
    private static final SingletonService instance = new SingletonService();

    //2. public으로 열어서 객체 인스터스가 필요하면 이 static 메서드를 통해서만 조회하도록
    //허용한다
    public static SingletonService getInstance() {
        return instance;
    }

    //3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다.
    private SingletonService() {}

    public void logic() {
        System.out.println(&quot;싱글톤 객체 로직 호출&quot;);
    }
}</code></pre>
<ul>
<li><code>private</code> 생성자를 사용해서 외부에서 임의로 <code>new</code> 키워드를 사용하지 못하도록 막는다.</li>
</ul>
<h3 id="2-싱글톤-패턴의-장점">2. 싱글톤 패턴의 장점</h3>
<hr>
<ul>
<li>인스턴스가 단 하나이기 때문에 인스턴스를 생성할때 드는 비용이 줄어든다.<ul>
<li>메모리 측면의 이점<ul>
<li><code>static</code>을 사용하여 별도의 메모리 영역을 받으면서 한번의 <code>new 연산자</code>로 인스턴스를 사용하기 때문에 <strong>메모리 낭비를 방지</strong>할 수 있다.</li>
</ul>
</li>
<li><strong>속도 측면의 이점</strong><ul>
<li>생성된 인스턴스를 사용할 때는 이미 생성된 인스턴스를 활용하여 속도 측면에 이점이 있다.</li>
</ul>
</li>
<li><strong>데이터 공유에 이점</strong><ul>
<li>전역 인스턴스이기 때문에 다른 클래스의 인스턴스들이 데이터를 공유할 수 있다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="✅-싱글톤-패턴의-단점">✅ 싱글톤 패턴의 단점</h3>
<hr>
<ul>
<li>싱글톤 패턴을 구현하는 코드가 추가된다.</li>
<li>의존 관계상 클라이언트가 구현체 클래스에 의존하게 된다.<ul>
<li>→ <code>DIP</code> 위반</li>
<li>→ <code>OCP</code> 위반할 가능성이 높다</li>
</ul>
</li>
<li><code>private</code> 생성자로 자식 클래스를 만들기 어렵다.</li>
<li>유연성이 떨어져서 안티패턴으로 불리기도 한다.</li>
<li>동시성 문제가 발생할 수 있다.</li>
</ul>
<h3 id="✅-싱글톤-패턴을-활용하는-사례">✅ 싱글톤 패턴을 활용하는 사례</h3>
<hr>
<p>싱글톤 패턴은 보통 객체가 <strong>리소스를 많이 차지하는 역할</strong>을 하는 무거운 클래스일때 사용된다.</p>
<p>대표적으로 <code>데이터베이스 연결 모듈</code>에 많이 사용된다.</p>
<p>데이터 베이스에 접속하는 작업은 무거운 작업에 속하며, 한번만 객체를 생성하고 돌려 쓰면 되지 굳이 여러번 생성할 필요가 없기 때문입니다.</p>
<p>이밖에도 <code>**디스크 연결**</code>, <code>**네트워크 통신**</code>, <code>**DBCP 커넥션 풀**</code>, <code>**스레드 풀**</code>, <code>**캐시**</code>, <code>**로그 기록 객체**</code> 등에 이용된다.</p>
<h3 id="❗-싱글톤-패턴-설계-시-주의점">❗ 싱글톤 패턴 설계 시 주의점</h3>
<blockquote>
<p>싱글톤 방식은 하나의 같은 객체 인스턴스를 공유하기 때문에 항상 상태를 유지(<code>stateful</code>) 하게 설계하면 안된다.</p>
</blockquote>
<hr>
<ul>
<li>특정 클라이언트에 의존적인 필드가 있으면 안된다.</li>
<li>특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다!</li>
<li>가급적 읽기만 가능해야 한다.</li>
<li>필드 대신에 자바에서 공유되지 않는, 지역변수, 파라미터, ThreadLocal 등을 사용해야 한다.</li>
</ul>
<pre><code class="language-java">package hello.core.singleton;

public class StatefulService {

    private int price; //상태를 유지하는 필드

    public int order(String name, int price){
        System.out.println(&quot;name = &quot; + name + &quot;price = &quot;+price);
        this.price = price; //여기가 문제!! -&gt; 상태를 유지하게 설계됨
    }

    public int getPrice() {
        return price;
    }
}</code></pre>
<pre><code class="language-java">public class StatefulServiceTest {

    @Test
    void statefulServiceSingleton() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(TestConfig.class);
        StatefulService statefulService1 = ac.getBean(StatefulService.class);
        StatefulService statefulService2 = ac.getBean(StatefulService.class);

        //ThreadA : A사용자 10000원주문
        statefulService1.order(&quot;userA&quot;, 10000);
        //ThreadA : B사용자 20000원주문
        statefulService2.order(&quot;userB&quot;, 20000);

        //ThreadA: 사용자A 주문 금액 조회
        int price = statefulService1.getPrice();
        //ThreadA: 사용자A는 10000원을 기대했지만, 기대와 다르게 20000원 출력
        System.out.println(&quot;price = &quot; + price);

        Assertions.assertThat(statefulService1.getPrice()).isEqualTo(20000);
    }
    static class TestConfig{
        @Bean
        public StatefulService statefulService() {
            return new StatefulService();
        }
    }
}</code></pre>
<ul>
<li>사용자 A가 10000원을 주문하고, 조회하기 전에 사용자 B가 20000원을 주문하면, <code>this.price = price</code> 때문에 A가 주문을 조회 했을때, <strong>10000원이 아닌 20000원이 나온다</strong>. → <code>price 필드</code>를 공유하기 때문이다.!</li>
</ul>
<aside>
💡 싱글톤으로 관리되는 스프링 `빈(객체)`은 항상 **`무상태(stateless)`**로 **설계해야한다.**

</aside>

<h2 id="2-싱글톤-컨테이너란">2. 싱글톤 컨테이너란?</h2>
<blockquote>
<p>싱글톤 패턴의 단점을 보완하기 위해 나온 것이 스프링의 <strong><code>싱글톤 레지스트리</code></strong>이다. <strong>스프링 컨테이너</strong>가 <code>싱글톤 레지스트리</code>의 역할을 하여 <strong>빈을 싱글톤으로 관리</strong>한다.</p>
</blockquote>
<hr>
<ul>
<li>스프링 컨테이너는 객체 인스턴스를 싱글톤으로 관리해준다.</li>
<li><strong>싱글톤 객체를 생성하고 관리하는 기능</strong>을 <code>**싱글톤 레지스트리**</code>라고 한다.</li>
<li>싱글톤 레지스트리 덕분에 싱글턴 패턴의 단점을 해결하면서 객체를 싱글톤으로 유지가 가능하다.</li>
<li><code>DIP</code>, <code>OCP</code>, 테스트, private 생성자로 부터 자유롭게 싱글톤을 사용할 수 있다.</li>
</ul>
<aside>
💡 📌 참고 : 스프링의 기본 빈 등록 방식은 싱글톤이지만, 싱글톤 방식만 지원하는 것은 아니다! **요청할 때 마다 새로운 객체를 생성해서 반환하는 기능도 제공**한다. → `빈 스코프`

</aside>

<h2 id="3-configuration">3. <strong>@Configuration</strong></h2>
<blockquote>
<p><code>@Configuration</code> 어노테이션를 클래스에 붙이면 <code>@Bean</code>객체들을 싱글톤으로 관리해준다.</p>
</blockquote>
<hr>
<pre><code class="language-java">@Configuration
  public class AppConfig {
      @Bean
      public MemberService memberService() {
          return new MemberServiceImpl(memberRepository());
      }
      @Bean
      public OrderService orderService() {
          return new OrderServiceImpl(
                  memberRepository(),
                  discountPolicy());
            }
      @Bean
      public MemberRepository memberRepository() {
          return new MemoryMemberRepository();
      }
}</code></pre>
<ul>
<li><code>memberService</code> 를 보면 <code>memberRepository</code> 를 호출한다.<ul>
<li>→ <code>MemoryMemberRepository</code> 를 생성 호출한다.</li>
</ul>
</li>
<li><code>orderService</code> 를 보면 <code>memberRepository</code>를 호출한다.<ul>
<li>→ <code>MemoryMemberRepository</code>  를 생성 호출한다.</li>
</ul>
</li>
</ul>
<p>이렇게 되면, 각각 다른 2개의 <code>MemoryMemberRepository</code>  가 생성되면서 싱글톤이 깨지는 것처럼 보인다.</p>
<p>하지만, <strong>테스트를 통해 확인 해본 결과는 같은 인스턴스를 가리킨다.</strong></p>
<p>이렇게 되는 이유는 <strong>@Configuration과 바이트코드 조작에 비밀이 있다.</strong></p>
<h3 id="-configuration과-바이트코드-조작">⁉ <strong>@Configuration과 바이트코드 조작</strong></h3>
<hr>
<pre><code class="language-java">@Test
    void configurationDeep() {
        // 이 과정에서 Appconfig 도 스프링 빈으로 등록된다
        ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        // Appconfig 조회
        AppConfig bean = ac.getBean(AppConfig.class);

        // 클래스 타입 출력
        System.out.println(&quot;bean = &quot; + bean.getClass());

    }
// 출력 - &gt; bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$f1bf9c1</code></pre>
<p>예상한 결과는 <code>class hello.core.Appconfig</code> 였지만, <strong>클래스명에 xxxCGLIB가 붙으면서 상당히 복잡해 진것</strong>을 볼 수 있다.</p>
<p>이는 스프링이 CGLIB 라는 바이트코드 조작 라이브러리를 사용해서 <strong>APPConfig 클래스를 상속받은 임의의 다른 클래스를 만들고 그 다른 클래스를 스프링 빈으로 등록한 것</strong>이다.</p>
<p><img src="https://velog.velcdn.com/images%2Fsorzzzzy%2Fpost%2F83fc2be9-d32c-41c2-8755-1f6d844a36ff%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-23%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.35.46.png" alt="https://velog.velcdn.com/images%2Fsorzzzzy%2Fpost%2F83fc2be9-d32c-41c2-8755-1f6d844a36ff%2F%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202021-08-23%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2012.35.46.png"></p>
<p>이처럼 AppConfig가 있는데 CGLIB라는 바이트 코드 조작 라이브러리를 가지고 상속받아서 아예 다른 클래스를 만들어 버린것이다.</p>
<p>그리고 <strong>그 조작한 클래스를 스프링 빈으로 등록</strong>한다!</p>
<ul>
<li><strong>만약 스프링 컨테이너에 해당 객체가 등록</strong>이 되어 있다면 → <strong>스프링 컨테이너에서 찾아서 반환</strong></li>
<li><strong>스프링 컨테이너에 해당 객체가 등록</strong>이 안되어 있다면 → <strong>클래스를 조작해서 스프링 컨테이너에 등록</strong>한다.</li>
</ul>
<aside>
💡 `@Bean`만 사용해도 스프링 빈으로 등록되지만, 싱글톤을 보장하지는 않음!(싱글톤을 보장하기 위해서는 `@Configuration`이 필요)

<p>→ 그냥 고민하지 말고, 스프링 설정 정보는 항상 <code>@Configuration</code> 을 사용하자! 설정 정보가 필요한 곳에는 무조건 넣자!</p>
</aside>

<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 컨테이너와 스프링 빈]]></title>
            <link>https://velog.io/@gudals-kim/3.-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B9%88</link>
            <guid>https://velog.io/@gudals-kim/3.-%EC%8A%A4%ED%94%84%EB%A7%81-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88%EC%99%80-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B9%88</guid>
            <pubDate>Wed, 09 Aug 2023 04:42:19 GMT</pubDate>
            <description><![CDATA[<h1 id="🍃-스프링-컨테이너">🍃 스프링 컨테이너</h1>
<blockquote>
<p><code>**스프링 컨테이너**</code> 는 자바 객체의 생명 주기를 관리하며, 생성된 자바 객체들에게 추가적인 기능을 제공하는 역할이다. 스프링에서는 자바 객체를 <code>**빈(Bean)**</code>이라고 부르며, <code>**IoC**</code>, <code>**DI**</code>와 같은 SOLID원칙을 지키기 위한 기술이 <code>**스프링 컨테이너**</code>에 적용되어 있다.</p>
</blockquote>
<hr>
<h2 id="1-스프링-컨테이너란">1. 스프링 컨테이너란?</h2>
<hr>
<p>기존 <code>객체의 생성주기</code>는 개발자가 <strong>new 연산자</strong>, <strong>인터페이스 호출</strong>, <strong>팩토리 호출 방식</strong>으로 <strong>객체를 생성하고 소멸</strong>해야 한다.</p>
<p>하지만 스프링에서는 스프링 컨테이너가 이 역할을 대신 해준다. 즉 IoC(제어 흐름을 외부에서 관리한다.)가 적용되어 있다. 또한 객체(빈)간의 의존 관계를 스프링 컨테이너가 런타임(실행중)에 알아서 만들어 준다.</p>
<h2 id="2-스프링-컨테이너의-생성-과정">2. 스프링 컨테이너의 생성 과정</h2>
<hr>
<pre><code class="language-java">//스프링 컨테이너 생성
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);</code></pre>
<ul>
<li><code>ApplicationContext</code>를 스프링 컨테이너라 한다.</li>
<li><code>ApplicationContext</code>는 인터페이스 이다.</li>
<li><code>AnnotationConfigApplicationContext</code>는 <code>ApplicationContext</code> 인터페이스의 구현체이다.</li>
<li><strong>스프링 컨테이너는 XML을 기반으로 만들 수 있고, 애노테이션 기반의 자바 설정 클래스로 만들 수 있다.</strong></li>
</ul>
<h3 id="✔-생성-스프링-컨테이너-생성">✔ [생성] 스프링 컨테이너 생성</h3>
<hr>
<p><img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHEsQS%2FbtrDc62Tlnx%2FJytgwtiR7L717rUPAIJKJ0%2Fimg.png" alt="이미지1"></p>
<pre><code class="language-java">//스프링 컨테이너 생성
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);</code></pre>
<ul>
<li>스프링 컨테이너를 <strong>생성할 때는 구성 정보를 지정</strong>해 주어야한다.</li>
<li>위 코드에서는 <code>AppConfig.class</code>가 구성 정보이다.</li>
</ul>
<h3 id="✔-등록-스프링-빈-등록">✔ [등록] 스프링 빈 등록</h3>
<hr>
<p><img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTFLUT%2FbtrC9K75BhP%2FNhAnokIPeO4mKDJZ0Q3XR1%2Fimg.png" alt="이미지2"></p>
<p>스프링 컨테이너는 구성정보(config.class 정보)를 사용해서 스프링 빈을 등록한다.</p>
<p>스프링 빈 저장소에 key(빈 이름) → value(빈 객체) 로 map과 같은 형태로 저장되어 있다고 생각하면 편하다.</p>
<p><strong>스프링 빈 규칙</strong></p>
<ul>
<li>빈 이름은 메서드 이름을 사용한다.</li>
<li>빈 이름을 직접 부여할 수 있다.</li>
<li>빈 이름은 항상 다른 이름을 부여 해야 한다.</li>
</ul>
<h3 id="✔-스프링-빈-의존-관계-설정">✔ 스프링 빈 의존 관계 설정</h3>
<hr>
<p><img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsPa4O%2FbtrDc7tYgrY%2FLUUwC8SJrETxsO8gZpOGBk%2Fimg.png" alt="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsPa4O%2FbtrDc7tYgrY%2FLUUwC8SJrETxsO8gZpOGBk%2Fimg.png"></p>
<ul>
<li>스프링 컨테이너는 구성 정보를 참고해서 의존관계를 주입한다.</li>
<li>단순히 자바 코드를 호출하는 것과 차이가 있다.(싱글톤 컨테이너)</li>
<li>스프링 빈을 등록하는 순간, 의존 관계 주입도 한번에 처리된다.</li>
</ul>
<h3 id="✔-조회-컨테이너에-등록된-빈-조회">✔ [조회] 컨테이너에 등록된 빈 조회</h3>
<hr>
<pre><code class="language-java">public class ApplicationContextInfoTest {
         //스프링 컨테이너 생성
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

    @Test
    @DisplayName(&quot;모든 빈 출력하기&quot;)
    void findAllBean() {
        String[] beanNames = ac.getBeanDefinitionNames();//스프링에 등록된 모든 빈 이름을 조회
        for (String beanName : beanNames ) {
            Object bean = ac.getBean(beanName);//빈 이름으로 빈 객체(인스턴스)를 조회
            System.out.println(&quot;name = &quot; + beanName + &quot;Object =&quot; + bean);
        }
    }

    @Test
    @DisplayName(&quot;직접 등록한 빈 출력하기&quot;)
    void findApplicationBean() {
        String[] beanNames = ac.getBeanDefinitionNames();
        for (String beanName: beanNames ) {

                        //getBeanDefinition: Bean에 대한 meta data 정보들을 반환한다
            BeanDefinition beanDefinition = ac.getBeanDefinition(beanName);

                         //사용자가 정의한 빈일 경우에만 if문 수행
            //Role ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
            //Role ROLE_INFRASTRUCTURE: 스프링이 내부에서 사용하는 빈
            if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION){ 
                Object bean = ac.getBean(beanName);
                System.out.println(&quot;name = &quot; + beanDefinitionName + &quot;Object =&quot; + bean);
            }

        }
    }

}</code></pre>
<p><strong>주요 메서드</strong></p>
<ul>
<li><code>ac.getBeanDefinitionNames()</code> : 스프링에 등록된 모든 빈 이름을 조회한다.</li>
<li><code>ac.getBean()</code> : 빈 이름으로 빈 객체를 조회한다.</li>
<li><code>ac.getBeanDefinition()</code> : Bean에 대한 meta data 정보를 반환한다.</li>
<li><code>ac.getBeansOfType()</code> : 사용하면 해당 타입의 모든 빈을 조회할 수 있다. (return : map)</li>
</ul>
<p><strong>빈 조회 규칙</strong></p>
<ul>
<li>부모 타입으로 조회하면 자식 타입도 함께 조회한다.<ul>
<li>→ 모든 자바 객체의 최고 부모인 Object 타입으로 조회하면, 모든 스프링 빈을 조회한다.</li>
</ul>
</li>
</ul>
<p>💡 실제로 <code>ApplictionContext</code>에서 직접 <code>getBean()</code>을 쓸 일은 별로 없다. 
→ <strong>주로 스프링이 자동으로 의존관계를 주입해주기 때문</strong>
단, 자동 주입에 대해 쉽게 이해하기 위해서는 한번쯤은 이해해야하며, 순수 java에서 spring container를 사용해야할때 사용된다.</p>
<h2 id="3--스프링-컨테이너-종류">3.  스프링 컨테이너 종류</h2>
<hr>
<p>스프링 컨테이너에는 <code>BeanFactory</code>와 <code>ApplicationContext</code>가 있습니다.</p>
<h3 id="1-beanfactory">1. BeanFactory</h3>
<ul>
<li>스프링 컨테이너의 최상위 인터페이스</li>
<li>스프링 빈을 관리하고 조회하는 역할을 담당한다.</li>
<li>getBean() 등의 빈 객체와 관련된 메서드를 해당 인터페이스가 제공한다.</li>
</ul>
<h3 id="2-applicationcontext">2. ApplicationContext</h3>
<ul>
<li>BeanFactory 기능을 모두 상속받아서 제공한다.</li>
<li>BeanFactory의 모든 기능을 포함하는 것은 물론이고 아래 추가 기능들을 제공한다.</li>
<li>대표적인 추가기능<ul>
<li><strong>**<code>Environment</code> : 프로파일(Profile)을 설정하고 어떤 것을 사용할지 선택할 수 있게 해주며, 소스 설정 및 프로퍼티 값을 가져오게 해준다.</strong></li>
<li><strong>**<code>MessageSource</code> : 메세지 설정 파일을 모아서 각 국가마다 로컬라이징을 함으로써 각 지역에 맞춤 메시지를 제공(메시지에 대한 국제화(i18n)을 제공하는 인터페이스)</strong></li>
</ul>
</li>
</ul>
<blockquote>
<p>💡 <code>BeanFacory</code>는 빈 관리 기능을 제공한다.
<code>ApplicationConext</code>는 빈 관리기능 (<code>BeanFactory</code>)와 더불어 편리한 <strong>부가기능을 더 제공</strong>한다.
→ <code>BeanFactory</code>를 직접 사용할 일은 거의 없다. 대부분 부가기능이 포함된 <code>ApplicationContext</code>를 사용한다.
→ 둘 다 스프링 컨테이너라고 부른다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링과 객체지향프로그래밍]]></title>
            <link>https://velog.io/@gudals-kim/2.-%EC%8A%A4%ED%94%84%EB%A7%81%EA%B3%BC-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@gudals-kim/2.-%EC%8A%A4%ED%94%84%EB%A7%81%EA%B3%BC-%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Wed, 02 Aug 2023 11:04:24 GMT</pubDate>
            <description><![CDATA[<h1 id="🍃-spring과-oopobject-oriented-programming">🍃 Spring과 OOP(Object Oriented Programming)</h1>
<blockquote>
<p>Spring의 큰 장점 중 하나는 자바의 장점인  <strong>OOP(객체지향프로그래밍)</strong>을 할 수 있다는 것이다.</p>
</blockquote>
<aside>
💡 `OOP(객체 지향 프로그래밍)` 이란 **문제를 여러 개의 객체 단위로 나눠 작업하는 방식**으로, 객체들이 서로 유기적으로 상호작용하는 프로그래밍 이론이다. 대표적으로 Java와 C#이 객체 지향 프로그래밍 언어이다.

</aside>

<h2 id="1️⃣-다형성polymorphism">1️⃣ 다형성(Polymorphism)</h2>
<blockquote>
<p>다형성이란 <strong>역할</strong>과 <strong>구현</strong>의 분리를 말한다.</p>
</blockquote>
<hr>
<p>다형성을 고려하고 객체를 설계할 때 <strong><code>Interface(역할)</code></strong>을 먼저 부여한 후 그 역할을 수행하는 <code>**Implementation(구현체)**</code>를 만들게 된다.</p>
<p>이러한 방법으로 설계를 한다면 클라이언트는 <code>**Interface(인터페이스)**</code>을 <strong>사용하기 때문</strong>에 인터페이스를 구현한 <code>**Implementation(구현체)**</code> <strong>내부에 대해서 알 필요가 없다.</strong> 또한 <strong>구현체를 변경할때 클라이언트의 코드는 전혀 영향을 받지 않는다</strong>는 장점이 있다.</p>
<pre><code class="language-java">public class MemberService {
    // private MemberRepository memberRepository = new MemoryMemberRepository();
    private MemberRepository memberRepository = new JdbcMemberRepository();
}</code></pre>
<p><code>MemoryMemberRepository</code>와 <code>JdbcMemberRepository</code>는 <code>MemberRepository</code>인터페이스를 구현한 <strong>구현체이다</strong>. 현재는 <code>JdbcMemberRepository</code> 구현체를 사용하고 있다.</p>
<p>이처럼 <strong>다형성을 활용</strong>하면 실행시점에 <strong>객체 인스턴스를 유연하게 바꿀 수</strong> 있고, 클<strong>라이언트 코드 변경 없이 서버의 구현 기능을 변경</strong>할 수 있기 때문에 <strong>확장에 유용</strong>하다.</p>
<p>하지만 <strong>순수한</strong> <strong>자바</strong>로는 <strong>SOLID 원칙</strong>을 지키지 못한다.</p>
<h2 id="2️⃣--solid-원칙">2️⃣  SOLID 원칙</h2>
<blockquote>
<p><code>SRP</code> <code>OCP</code> <code>LSP</code> <code>ISP</code> <code>DIP</code> 로 <code>OOP</code> 할때 지켜야하는 원칙이다.</p>
</blockquote>
<hr>
<h3 id="srpsingle-reponsibility-prinicipal">SRP(Single Reponsibility prinicipal)</h3>
<blockquote>
<p><strong>단일 책임 원칙 :</strong> 한 클래스는 하나의 책임만 져야 한다.</p>
</blockquote>
<p>하나의 책임이란 말이 모호하지만, 변경을 기준으로한다. </p>
<p>어떤 기능이 <strong>외부 클래스</strong>나 <strong>라이브러리에 종속적</strong>이게 된다면 라이브러리나 외부 클래스가 <strong>변경</strong>이 된다면 기능에 영향이 있다. 이를 <strong>최소화 할 수 있도록 클래스를 설계</strong>하는 것이 원칙이다.</p>
<hr>
<h3 id="ocp-open-closed-principal">OCP (Open Closed Principal)</h3>
<blockquote>
<p><strong>개방 폐쇄 원칙</strong> : 소프트웨어 요소는 <strong>확장에는 열려</strong>있으나 <strong>변경에는 닫혀</strong>있어야 한다.</p>
</blockquote>
<pre><code class="language-java">public class MemberService {
    // private MemberRepository memberRepository = new MemoryMemberRepository();
    private MemberRepository memberRepository = new JdbcMemberRepository();
}</code></pre>
<p>이처럼 <code>MemberService (클라이언트)</code> 에서 <code>MemoryMemberRepository(구현체)</code> 에서 확장된 기능이 구현되어 있는 <code>JdbcMemberRepository(구현체)</code>로 교체를 했어도 결국 <strong>클라이언트에서 구현체를 바꿔야</strong>하기 때문에 순수 자바 만으로 <code>OCP</code>를 순전히 지키기 힘들다.</p>
<aside>
💡 **한계 → 순수 자바 코드만으로는** 역할과 분리를 통해 확장을 해도 결국 구현 객체를 변경하려면 클라이언트 코드를 변경해야 하기 때문에 `**OCP`를 지킬 수 없다.

<p>해결 → Spring을 사용한다면 이 부분을 해결**해 준다.</p>
</aside>

<hr>
<h3 id="lsp-liskov-substitution-principal">LSP (Liskov Substitution Principal)</h3>
<blockquote>
<p><strong>리스코프 치환 원칙</strong> : 다형성에서 하위 클래스는 인터페이스의 규약을 다 지켜야한다.</p>
</blockquote>
<p>같은 인터페이스나 클래스를 상속받는다면 구현체들은 인터페이스 및 클래스의 규칙을 지켜서 개발해야한다.</p>
<hr>
<h3 id="isp-interface-segregation-principal">ISP (Interface Segregation Principal)</h3>
<blockquote>
<p><strong>인터페이스 분리 원칙</strong> : 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나 보다 낫다.</p>
</blockquote>
<p>예를 들어 <code>Car</code>라는 인터페이스를 <code>운전 인터페이스</code>, <code>정비 인터페이스</code>로 <strong>분리</strong>한다. </p>
<p>그러면 클라이언트도 <code>운전 클라이언트</code>, <code>정비 클라이언트</code>로 <strong>분리</strong>가 되는데 이러면 <strong>정비 클라이언트가 변해도 운전 클라이언트에 영향</strong>을 주지 않는다.</p>
<p> <strong>즉 인터페이스가 명확해지고, 대체 가능성이 높아진다.</strong></p>
<aside>
💡 **한계** → 기능 별로 상세하게 인터페이스를 나누는 것 `ISP`를 잘 따르는 것이지만, 그렇게 된다면 **추상화 비용**이 발생한다.

</aside>

<aside>
💡 `**추상화 비용이란?` 
성능에 대한 비용**이 아닌 **복잡도에 대한 부분**을 말한다.
추상화가 없다면 그냥 코드를 따라가면 되는데, 추상화가 있다면 추상 인터페이스를 보고 **어떤 구현체가 실제 동작할지 또 추가로 찾아야하는 과정을 거쳐야한다.**

<p>즉, <strong>추상화를 한다</strong>면 구현체를 갈아끼울 수 있으서 <strong>확장성이 늘어나기 때문에 유지보수하기 좋아지는 부분</strong>도 있지만 반대로 <strong>필요하지 않은 곳 까지 추상화하게 된다</strong>면 코드를 <strong>유지보수하기 더 어려워 질 수 있다.</strong> </p>
<p>좋은 개발자의 역량 중 하나가 이러한 부분을 적절히 잘 선택하는 것이다.</p>
</aside>

<hr>
<h3 id="dipdependency-inversion-principal">DIP(Dependency Inversion Principal)</h3>
<blockquote>
<p><strong>의존관계 역전 원칙</strong> : 구현 클래스에 의존하지 않고 인터페이스를 의존하라</p>
</blockquote>
<p>만약 구현 클래스를 의존하면 <code>**OCP</code>를 지키기 어려울 뿐<strong>만 아니라 **변경이 아주 어려워</strong>진다. 즉 클라이언트가 구현 클래스는 모르고 인터페이스를 의존하여 사용하라는 뜻이다.</p>
<pre><code class="language-java">public class MemberService {
    private MemberRepository memberRepository = new MemoryMemberRepository();
}</code></pre>
<p>여기서 <code>**MemberService(클라이언트)**</code>는 <strong><code>MemberRopository (인터페이스)</code></strong>를 의존하고 있지만 이를 구현한 <strong><code>MemoryMemberRepository(구현체)</code></strong>도 의존하고 있다</p>
<aside>
💡 **한계** → 순수 자바 코드로는 `DIP`를 지키기 힘들다.

<p><strong>해결 → Spring을 사용한다면 이 부분을 해결</strong>해 준다.</p>
</aside>

<hr>
<h2 id="3️⃣-spring-의-해결-방법">3️⃣ Spring 의 해결 방법</h2>
<blockquote>
<p><strong>스프링</strong>은 순수 자바의 한계점(<code>OCP</code>,<code>DIP</code>) 들을 <strong>다음 기술로 해결</strong>해준다.</p>
</blockquote>
<ul>
<li><code>DI(Dependency Injection)</code></li>
<li><code>DI Container</code></li>
</ul>
<p>이 기술들로 <strong>클라이언트 코드의 변경없이 기능을 확장</strong>할 수 있다.</p>
<h3 id="iocinversion-of-control">IoC(Inversion of Control)</h3>
<hr>
<blockquote>
<p><code>IoC</code>란 Inversion of Control의 줄임말이며, 제어의 역전이라고 한다.</p>
<p><strong>메소드나 객체의 호출작업</strong>을 개발자가 결정하는 것이 아니라,  <strong>외부에서 결정되는 것</strong>을 의미한다.</p>
</blockquote>
<pre><code class="language-java">public class MemberService {
    // 구현체 의존 DIP 위반
    // 구현체 변경을 하려면 클라이언트에서 수정해야 하므로 OCP 위반
    private MemberRepository memberRepository = new JdbcMemberRepository();
    // private MemberRepository memberRepository = new MemoryMemberRepository();
}</code></pre>
<p>위 코드는 <strong>클라이언트가 필요한 서버 구현 객체를 스스로 생성하고, 연결하고, 실행하였다.</strong> 즉 구현 객체가 프로그램의 제어 흐름을 <strong>스스로 조종</strong>하였다.</p>
<p>여기에 <code>IoC</code>를 적용한다면 </p>
<pre><code class="language-java">public class AppConfig {

    public MemberRepository memberRepository() {
        return new JdbcMemberRepository();
    }
    public MemberService memberService() {
        return new MemberService(memberRepository());
    }
}</code></pre>
<p><code>AppConfig class</code>를 만들어서 <code>JdbcMemberRepository(구현체)</code>를 대신 생성해서 <code>MemberService(클라이언트)</code>에 주입할 수 있도록 만들어주었다.</p>
<p>즉, <code>AppConfig class</code>는 <strong>프로그램의 제어를 담당하는 클래스</strong>이다.</p>
<h3 id="di-dependency-injection">DI (Dependency Injection)</h3>
<blockquote>
<p>의존성 주입이라는 뜻으로, <code>IOC</code>를 구현하기 위해 사용하는 기법 중 하나이다.</p>
</blockquote>
<pre><code class="language-java">public class MemberService {
    // 클라이언트는 인터페이스에만 의존한다. DIP 지킴
    // 구현체를 변경해도 클라이언트의 변화는 없다. OCP 지킴
    private final MemberRepository memberRepository;

        //외부에서 의존하는 객체를 주입받는다.        
        public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
    public String save(String username) {
        return memberRepository.save(username);
    }
}</code></pre>
<p>이와 같이 의존하는 객체를 외부에서 주입받도록 설계하는 기술이 DI 이다. </p>
<aside>
💡 IOC를 적용한 `MemberService(클라이언트)`를 보면 `JdbcMemberRepository`를 찾아 볼수 없고 모두 `MemberRepository(인터페이스)`를 의존하고 있다 → **`DIP`를 지키고 있다.**

</aside>

<aside>
💡  `JdbcMemberRepository`, `MemoryMemberRepository` 중 둘 중 어떤 구현체를 사용하는 가에 대한 코드가 전혀 없기 때문에 **구현체를 바꾸어도** **클라이언트 코드의 변경이 없다**. → **`OCP`를 지키고 있다.**

</aside>

<h3 id="ioc-container">IoC container</h3>
<blockquote>
<p>스프링 프레임워크도 <strong>객체에 대한 생성 및 생명주기를 관리</strong>할 수 있는 기능을 제공하고 있다. 즉, <code>IoC 컨테이너 기능을 제공</code>한다.</p>
</blockquote>
<p><strong>인스턴스 생성부터 소멸까지의 인스턴스 생명주기 관리를 개발자가 아닌 컨테이너가 대신 해줍니다.</strong></p>
<p><strong>객체관리 주체가 프레임워크(Container)가 되기 때문에 개발자는 로직에 집중할 수 있는 장점이 있습니다.</strong></p>
<ul>
<li>IoC 컨테이너는 객체의 생성을 책임지고, 의존성을 관리한다.</li>
<li>POJO의 생성, 초기화, 서비스, 소멸에 대한 권한을 가진다.</li>
<li>객체 생성 코드가 없으므로 TDD가 용이하다.</li>
</ul>
<pre><code>💡 **“컨테이너”**란? 
보통 객체의 생명주기를 관리, 생성된 인스턴스들에게 추가적인 기능을 제공하도록 하는 역할</code></pre><pre><code>💡 **“POJO”** 란?
주로 **특정 자바 모델이나 기능, 프레임워크를 따르지 않는 Java Object를 지칭**한다.
Java Bean 객체가 대표적이다.</code></pre>]]></description>
        </item>
    </channel>
</rss>