ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • @Configuration
    개발/Spring 2023. 5. 10. 22:01

    테스트 코드를 작성하는데, 클래스에 @Configuration을 붙이지 않아도 getBean 메서드로 빈이 획득됐다.

    관련 내용을 찾아 보니 공식 문서에 꽤나 친절하게 설명이 있었다.

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

     

    요약하자면 @Configuration이 붙은 클래스는 정식 스프링 빈이 된다. 해당 클래스를 부모 클래스로 하는 CGLIB(라이브러리)가 적용된 서브 클래스가 반환된다. 정식 스프링 빈으로 싱글톤으로 동작한다. 클래스와 메서드는 final이나 private으로 선언되면 안 된다.

     

    싱글톤 동작은 다음 테스트 코드가 통과하는 것에서 확인할 수 있다.

    하지만 SingletonBean 클래스에 @Configuration을 붙이지 않으면

    각 빈에서 생성된 NetworkClient 클래스의 빈은 전부 다르기 떄문에 테스트를 통과 못한다.

    public class WrapperNetworkClient {
        private final NetworkClient networkClient;
    
        public WrapperNetworkClient(NetworkClient networkClient) {
            this.networkClient = networkClient;
        }
    
        public NetworkClient getNetworkClient() {
            return networkClient;
        }
    }
    //////////////////////////////////////////////////////////////////
    
    public class SingletonBean {
        @Bean
        public NetworkClient networkClient() {
            return new NetworkClient();
        }
    
        @Bean
        public WrapperNetworkClient wrapperNetworkClient( ){
            return new WrapperNetworkClient(new NetworkClient());
        }
    }
    
    // Test
    public class SingletonTest {
        @Test
        void findSingletonBean() {
            ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(SingletonBean.class);
    
            NetworkClient singletonBean1 = context.getBean(NetworkClient.class);
            NetworkClient singletonBean2 = context.getBean(WrapperNetworkClient.class).getNetworkClient();
    
            System.out.println("singletonBean1 = " + singletonBean1);
            System.out.println("singletonBean2 = " + singletonBean2);
    
            Assertions.assertThat(singletonBean1).isSameAs(singletonBean2);
        }
    }

     

    만약에 SingletonBean에서 NetworkClient 빈만 생성될 때는

    SingletonTest에서 getBean을 할 때마다 얻어지는 빈은 매번 같은 것이 나온다.

    다음 테스트는 통과한다.

    public class SingletonTest {
        @Test
        void findSingletonBean() {
            ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(SingletonBean.class);
    
            NetworkClient singletonBean1 = context.getBean(NetworkClient.class);
            NetworkClient singletonBean2 = context.getBean(NetworkClient.class);
    
            System.out.println("singletonBean1 = " + singletonBean1);
            System.out.println("singletonBean2 = " + singletonBean2);
    
            Assertions.assertThat(singletonBean1).isSameAs(singletonBean2);
    
            context.close();
        }
    
        static class SingletonBean {
            @Bean
            NetworkClient networkClient() {
                return new NetworkClient();
            }
        }
    }

     

    클래스에서 @Configuration을 제거하거나 @Component를 붙이면 @Bean 메서드는 lite 모드에서 처리된다.

    lite 모드의 빈 메서드는 @Configuration의 빈 메서드와 달리 같은 클래스에서 상호 참조가 지원되지 않고

    표준적인 자바 메서드로 동작한다. 하기 이미지의 오류에서 확인할 수 있다.

    상기 코드에서 보이듯 return new NetworkClient()를 해야 오류가 사라진다.

    @Configuration을 붙이지 않았으므로 스프링은 CGLIB 프록시를 통해 호출을 가로채지 않는다.

    댓글

Designed by Tistory.