스프링 핵심원리 기본편 -5

조은지·2022년 3월 10일
0

스프링 핵심원리

목록 보기
3/3

Section5 - 싱글톤 컨테이너

싱글톤 패턴

  • 클래스의 인스턴스가 딱 1개만 생성되는 것을 보장하는 디자인 패턴
  • 싱글톤 패턴을 적용하면 고객의 요청이 올 때 마다 객체를 생성하는 것이 아니라, 이미 만들어진 객체를 공유해서 효율적으로 사용할 수 있다.

순수 자바에서 싱글톤 패턴의 문제점

  • 싱글톤 패턴을 구현하는 코드 자체가 많이 들어간다.
  • 의존관계상 클라이언트가 구체 클래스에 의존한다. => DIP위반
  • 클라이언트가 구체 클래스에 의존해서 OCP원칙을 위반할 가능성이 높다.
  • private 생성자로 자식 클래스를 만들기 어렵다.
  • 결론적으로 유연성이 떨어진다.

DIP 위반 관련 질문

  • DIP : 구체 클래스에 의존하지 말고 인터페이스에 의존해야 하는 원칙
  • AppConfig의 역할을 하는 클래스를 따로 두게 되면 DIP 위반을 피할 수 있다.
  • DIP의 핵심은 클라이언트가 구체 코드에 의존하지 않고 변경할 수 있으면 된다.

싱글톤 컨테이너

  • 스프링 컨테이너는 싱글톤 컨테이너 역할을 한다. 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라고 한다.
  • 스프링 컨테이너를 통해서 싱글톤 패턴의 단점을 해결하고 객체를 싱글톤으로 유지할 수 있다.

싱글톤 방식의 주의점

  • 싱글톤 객체는 상태를 stateful하게 설계하면 안된다.
  • 특정 클라이언트에 의존적인 필드가 있으면 안된다.
    다시 말해 특정 클라이언트가 값을 변경할 수 있는 필드가 있으면 안된다.
    - 필드 대신 자바에서 공유되지 않는 지역변수, 파라미터, 쓰레드로컬 등을 사용해야 한다.

(질문)TestConfig에서 @Configuration이 없어도 등록이 된 이유

AnnotationConfigApplicationContext( TestConfig.class ) 

위의 코드에서 스프링컨테이너에 직접 빈을 등록해주었기 때문에 가능하다.

이와 같은 경우에도 싱글톤으로 관리가 된다.

@Configuration과 싱글톤

  • @Configuration은 싱글톤을 위해 존재한다.
@Test
 void configurationTest() {
 ApplicationContext ac = new
AnnotationConfigApplicationContext(AppConfig.class);
 MemberServiceImpl memberService = ac.getBean("memberService",
MemberServiceImpl.class);
 OrderServiceImpl orderService = ac.getBean("orderService",
OrderServiceImpl.class);
 MemberRepository memberRepository = ac.getBean("memberRepository",
MemberRepository.class);
 //모두 같은 인스턴스를 참고하고 있다.
 System.out.println("memberService -> memberRepository = " +
memberService.getMemberRepository());
 System.out.println("orderService -> memberRepository = " +
orderService.getMemberRepository());
 System.out.println("memberRepository = " + memberRepository);
 //모두 같은 인스턴스를 참고하고 있다.
 
assertThat(memberService.getMemberRepository()).isSameAs(memberRepository);
 
assertThat(orderService.getMemberRepository()).isSameAs(memberRepository);
 }

테스트 코드 작성 시 orderService에서도 memberRepository를 사용하지만 인스턴스 생성은 1번씩만 된 것을 볼 수 있다. => CGLIB의 사용

(질문) @Configuration과 @Component의 차이

참고 링크 - https://yhmane.tistory.com/129

[정리]

  • @Component와 @Configuration은 큰 차이는 없다.
  • @Configuration 내에 @Component가 정의되어있다. => @Component와 @Bean을 비교하는 것이 맞다.

Component와 Bean
https://youngjinmo.github.io/2021/06/bean-component/

@Component

  • 개발자가 직접 작성한 클래스를 bean 등록하고자 할 경우 사용

@Configuration + @Bean

  • 외부라이브러리 또는 내장 클래스를 bean으로 등록하고자 할 경우 사용. - 1개 이상의 @Bean을 제공하는 클래스의 경우 반드시 @Configuraton을 명시

그러나 개발자가 직접 작성한 클래스를 @Configuration+@Bean으로 등록할 수도 있다.

(질문) @Configuration을 없애도 싱글톤이 유지되는 이유

  • 각각의 빈들은 @Configuration이 없어도 싱글톤으로 유지된다.
    @Configuration을 등록해줘야 하는 이유?

TestClass에서 AppConfig를 직접 등록하는 경우

@Bean
    public MemberRepository memberRepository() {
        System.out.println("AppConfig.memberRepository");
        return new MemoryMemberRepository();
    }

스프링이 빈을 등록할 때 memberRepository()를 호출한다.

 @Bean
    public MemberService memberService() {
        System.out.println("AppConfig.memberService");
        return new MemberServiceImpl(memberRepository());
    }

그러나 memberService에서 memberRepository()를 호출하게 되면 내부에서 new ~로 새로운 객체가 생성된다.

이 문제를 해결해주는 것이 @Configuration이다.

  • 이 애노테이션을 사용하면 memberRepository()와 같은 메서드 호출을 중간에 가로챌 수 있다. => 스프링 컨테이너를 통해서 빈을 찾아온다.

@Configuration과 바이트코드 조작

  • AnnotationConfigApplicationContext에 파라미터로 넘긴 값은 스프링 빈으로 등록된다. 따라서 AppConfig도 스프링 빈이 된다.
    bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd479d70
AppConfig 빈을 조회해보면 뒤에 CGLIB가 붙은 것을 볼 수 있다. 
=> 내가 만든 클래스가 아니라 스프링이 CGLIB라는 바이트코드 조작 라이브러리를 사용해서 AppConfig를 상속받은 임의의 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한 것이다. 

**이를 통해서 단순 자바 코드로 호출되는 memberRepository()를 빈으로 대체해서 전달해줄 수 있게 된다. **

0개의 댓글