Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

@Configuration, 싱글톤, 바이트코드 조작 본문

인프런/[인프런] Spring 핵심원리 이해

@Configuration, 싱글톤, 바이트코드 조작

Seung__ 2021. 7. 28. 00:29

1. AppConfig에서 method호출할 때 마다 인스턴스가 생성?


  • 기존에 작성한 AppConfig를 보면 memberRepository를 두 번 호출한다.
  • 그러면 MemoryMemberRepository가 두 번 생성되나????
  • 엥? 싱글톤인데??? 깨지나???
  • 스프링 컨테이너는 싱글톤 보장해준다고 했는데..?

 

 

2. 그러면 두 클래스에 들어가는 memberRepository가 같은지 보자.


public class ConfigurationSingletonTest {

    @Test
    void configurationTest(){
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

        MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
        OrderServiceImpl orderService = ac.getBean("orderService", OrderServiceImpl.class);

        MemberRepository memberRepository1 = memberService.getMemberRepository();
        MemberRepository memberRepository2 = orderService.getMemberRepository();
        MemberRepository memberRepository = ac.getBean("memberRepository", MemberRepository.class);

        System.out.println("memberService --> memberRepository1 = " + memberRepository1);
        System.out.println("orderService --> memberRepository2 = " + memberRepository2);
        System.out.println("memberRepository = " + memberRepository);

    }
}
  • 두 빈에 들어간 memberRepository는 동일하고, memberRepository bean과 동일하다!!
memberService --> memberRepository1 = hello.core.member.MemoryMemberRepository@4b45dcb8
orderService --> memberRepository2 = hello.core.member.MemoryMemberRepository@4b45dcb8
memberRepository = hello.core.member.MemoryMemberRepository@4b45dcb8

 

 

3. 어떻게 한겨?


로직대로 실행되는게 아닌 것 같다.

memberRepository의 인스턴스는 모두 같은 인스턴스가 공유되어 사용된당

로직대로라면 두 번 호출되어 memberRepository의 인스턴스가 달라야 할 것 같은데..

 

각 메서드가 몇 번 호출되는지 보자.

@Configuration
public class AppConfig {

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

    @Bean
    public OrderService orderService(){
        System.out.println("call AppConfig.orderService");
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

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

    @Bean
    public RateDiscountPolicy discountPolicy() {
        return new RateDiscountPolicy();
    }

}

응? 예상과 다르다.

call AppConfig.memberService
call AppConfig.memberRepository
call AppConfig.orderService

 

 

4. @Configuration, 바이트코드 조작


  • 스프링 컨테이너는 싱글톤 레지스트리 이다. 
  • 따라서 스프링 빈이 싱글톤이 되도록 보장해줘야 함.
  • 자바 코드만 보면.. 메서드 호출될 때 마다 생성되어야 하는데..
  • 이 문제를 해결하기 위해 스프링은 클래스 바이트코드를 주작한다.
  • 핵심은! @Configuration 붙인 AppConfig이다.
  • AppConfig도 bean으로 등록된다. appConfig bean의 클래스를 찍어보자.
      @Test
        void configurationDeep(){
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
            AppConfig bean = ac.getBean(AppConfig.class);
    
            System.out.println("bean = " + bean.getClass());
        }​
     

음? 뒤에 EnhancerBySpringCGLIB이 뭐지...

bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$58fbf5a5
  • xxxCGLIB이 붙었다.
  • 이것은 내가 만든 클래스가 아니라 스프링이 CGLIB이라는 바이트코드 조작 라이브러리를 사용하여
  • AppConfig 클래스를 상속받은 다른 클래스를 만들고 그 다른 클래스를 빈으로 등록한 것!
  • 즉, 스프링 컨테이너에 AppConfig$$EnhancerBySpringCGLIB이라 쓰고 AppConfig라 읽음.
  • 즉 @Bean이 붙은 메서드 마다 이미 스프링 빈이 존재하면 존재하는 빈을 반환하고
  • 스프링 빈이 없으면 생성해서 빈으로 등록하고 반환하는 코드가 동적으로 만들어진다.

 

5. @Configuration 안붙이면??


  • CGLIB안돌아가서 싱글톤 보장 못 함!
  • memberRepository처럼 의존관계 주입이 필요해서 메서드를 직접 호출할 때 싱글톤 보장 못함!
  • 항상 붙이자 ㅋㅋㅋ

 

6. GitHub : 210727 Singleton, @Configuration


 

GitHub - bsh6463/SpringCoreFunction

Contribute to bsh6463/SpringCoreFunction development by creating an account on GitHub.

github.com

 

Comments