• 티스토리 홈
starryeye
  • 프로필사진
    starryeye
    • 분류 전체보기 (189)
      • C++ (17)
      • Java (24)
      • OOP (5)
      • Spring Reactive Stack (12)
        • Reactive Streams (3)
        • Netty (4)
        • Reactor (1)
        • Webflux (3)
        • DB, Cache 연동 (1)
      • Spring (90)
        • Core (17)
        • MVC (33)
        • Client (2)
        • Security (4)
        • DB, Cache 연동 (33)
      • DataBase (12)
        • RDBMS (2)
        • NoSQL (10)
      • Message Broker (6)
      • Web (4)
      • Network (4)
      • 대규모 시스템 설계 (15)
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    • 최근 공지
        등록된 공지가 없습니다.
      # Home
      # 공지사항
      #
      # 태그
      # 검색결과
      # 방명록
      • @Configuration 와 싱글톤
        2023년 07월 13일
        • starryeye
        • 작성자
        • 2023.07.13.:04
        반응형

         

        @Configuration 은 스프링 컨테이너에 스프링 빈을 등록할 수 있도록 해주는 어노테이션이다.

        @Configuration 이 적용된 클래스 내부에

        다수의 @Bean 이 적용된 메서드가 있으면 스프링 빈으로 등록해준다.

        @Bean 이 적용된 메서드가 하는 역할은

        반환되는 객체를 해당 메서드의 이름을 가진 스프링 빈으로 등록한다.

         

        <참고>

        @Bean 은 스프링 빈으로 등록되는 클래스에 작성하여도 동작한다.

        (@Component 적용된 클래스 내부에 작성)

         

        본격적으로 이번 포스팅 주제인..

        @Configuration 어노테이션의 이해도를 높여보자.

         

        @Configuration
        public class AppConfig {
            @Bean
            public MyBean myBean() {
                return new MyBean();
            }
        
            @Bean
            public MyOtherBean myOtherBean() {
                return new MyOtherBean(myBean());
            }
            
            @Bean
            public MyAnotherBean myAnotherBean() {
            	return new MyAnotherBean(myBean());
            }
        }

        위와 같은 코드가 있다.

         

        myOtherBean 메서드에서 해당 클래스의 내부 메서드인 myBean() 을 호출하고 있다..

         

        Spring 에서 @Configuration, @Bean 을 사용하던..

        @Component 를 사용하던 Bean Scope 를 기본으로 두면 싱글톤이다.

         

        하지만, 코드를 보면 분명히

        MyOtherBean 생성자와 MyAnotherBean 생성자에서

        각각 myBean() 메서드를 호출을 하고 있는 것을 볼 수 있다.

         

        그래서 코드만 해석하자면 최종적으로 스프링 빈 등록 시...

        myOtherBean 이름의 bean 과 myAnotherBean 이름의 bean 에

        서로 다른 MyBean 객체가 주입되는것 처럼 보인다.

         

        그러면.. 스프링 컨테이너가 MyBean 객체를 싱글톤으로 관리한다는 말에 위배된다.

        그리고 myBean 메서드는 로그를 찍어보면 1회만 호출된다...

        이것을 어떻게 가능하게 하는지 알아보겠다.

         

        @Configuration 어노테이션을 뜯어보면,

        내부에 proxyBeanMethods 라는 요소가 있는데 이 값은 기본이 true 이다.

        해당 요소가 true 이면..

        @Configuration 을 적용한 객체(AppConfig)를 빈으로 등록할 때 (@Configuration 도 @Component 를 내장하고 있다.)

        CGlib 을 사용한 동적 프록시 객체로 등록하게된다.

        따라서 스프링 컨테이너에 빈을 등록하기 위해

        @Bean 어노테이션이 붙은 빈을 생성하고 반환해주는 메서드가 호출되기 전후로

        무엇인가를 해줄 수 있게 되는 것이다.

         

        <참고>

        실제로 proxyBeanMethods 요소의 값을 false 로 주면 서로 다른 MyBean 객체가 주입된다.

        그리고 AppConfig 객체가 스프링 빈으로 등록될 때,

        동적으로 생성된 프록시 객체가 아닌 원본 객체가 빈으로 등록된다.

         

        그 무엇인가는 알고 나면 간단하다.

        내부적으로 myBean 이름을 가진 빈이 아직 생성되지 않았다면 생성하고

        내부적으로 myBean 이름을 가진 빈이 생성되어 있으면 해당 객체를 그대로 사용한다.

        (내부적으로 맴버 변수로.. 캐시 성격의 key-value 컨테이너 사용 추측..)

        -> 즉, 이미 생성되어 있다면 원본 객체의 myBean() 메서드를 호출 하지 않는다. 그래서 싱글톤을 보장할 수 있는 것이다.

         

         

         

        여기서 좀 더 생각해보자..

        스프링 AOP 를 배웠다면 위화감이 들 수도 있다.

         

        스프링 AOP 에서는 내부 메서드를 호출하면 AOP 가 적용되지 않는다고 알고있다.

        this.myBean() 으로 직접호출이 되어버리기 때문이다.

         

        그래서 아래와 같이 생각해볼 수 있다.

        내부 메서드를 호출 하고 있기 때문에 AOP 가 적용되지 않으므로..

        포인트컷에 의한 어드바이스가 동작하지 않는다.

        즉..

        myBean() 은 내부 메서드 이므로 뭔가 프록시 처리가 안되고 제대로 동작이 잘 안될 것만 같다..

         

        실험을 해본 결과..

        AppConfig 는 원본 객체를 호출 하지 않는다..

        -> @Bean 이 적용된 메서드 내부에서 this 로 로그를 남겨보면.. 원본객체가 아닌 CGlib 객체로 나온다..

        즉, CGlib 를 사용하여 원본 객체를 상속하여 객체를 만들었지만 원본 객체를 따로 만들고 원본 객체를 호출 안함

        그래서 내부 호출을 하더라도 CGlib 에 의해 만들어진 객체에서 그대로 호출되는 것으로 생각된다.

         

        <실제로 확인>

        기본적으로 @Transactional 적용된 객체는 프록시 객체(by CGlib)와 원본 타겟 객체가 서로 분리 되어있다.

        프록시 객체에서 원본 객체로의 참조 관계가 명확하게 존재한다.

        하지만, @Configuration 의 경우엔.. 좀 다르다.

        상속관계를 이용한 참조? 로 원본객체를 대신한다....

        따라서 따로 생성된 원본객체가 없고 프록시만 존재하는데

        원본 객체를 대신하여 super 를 이용한다고 확인 되었다.

         

        -> 확인 가능 소스코드 경로

        org.springframework.context.annotation.ConfigurationClassEnhancer.java 파일에서

        private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback 클래스의

        public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs, MethodProxy cglibMethodProxy) 메서드에

        주석과 코드를 보면 이해가 될 것이다.

        한번도 생성안하면 invokeSuper, 생성해놨다면 캐싱되어있는 저장소에서 꺼내서 사용

         

         

        마지막으로 실험한 코드와 그에 따른 로그를 보여주고 마무리 하겠다.

         

        proxyBeanMethods=true 인 경우..

         

        예상한대로.. 모든 빈이 싱글톤으로 유지되고 있음을 알 수 있다.

        MyBean 생성자와 myBean 메서드는 1회 호출 되었음을 알 수 있다.

        또한, AppConfig 내부 메서드에서 찍은 this 에 CGlib 로 나타난다...

        -> 글쓴이가 원본 객체의 메서드를 호출하지 않는 것 같다고 생각한 이유..

         

         

        proxyBeanMethods=false 인 경우..

        AppConfig 는 CGlib 로 생성되지 않았음을 알 수 있다. (원본 객체)

        myBean 메서드가 호출이 중복적으로 나타나고 의존하는 객체에 서로다른 인스턴스가 주입되고 있다.

        또 눈여겨 보면 좋은 점은 최초로 생성된 객체가 스프링 빈으로 등록되고.. 해당 스프링 빈은 싱글톤이다.

        -> 지금 논점은 @Configuration 내부에서 싱글톤을 유지하냐 마냐이다.

        -> 당연히 스프링 컨테이너에 등록된 스프링 빈은 싱글톤이다.

         

         

         

        https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html

         

        https://docs.spring.io/spring-framework/reference/core/beans/java/configuration-annotation.html#beans-java-further-information-java-config

         

         

         

        반응형

        'Spring > Core' 카테고리의 다른 글

        Spring 은 SOLID 원칙을 잘 지키도록 도와준다.  (1) 2023.11.14
        @Async, TaskExecutor, CompletableFuture  (0) 2023.06.17
        Spring AOP 정의  (0) 2022.11.29
        Spring에서 프록시 사용 6  (0) 2022.11.29
        Spring에서 프록시 사용 5  (0) 2022.11.20
        다음글
        다음 글이 없습니다.
        이전글
        이전 글이 없습니다.
        댓글
      조회된 결과가 없습니다.
      스킨 업데이트 안내
      현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
      ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
      목차
      표시할 목차가 없습니다.
        • 안녕하세요
        • 감사해요
        • 잘있어요

        티스토리툴바