-
@Configuration개발/Spring 2023. 5. 10. 22:01
테스트 코드를 작성하는데, 클래스에 @Configuration을 붙이지 않아도 getBean 메서드로 빈이 획득됐다.
관련 내용을 찾아 보니 공식 문서에 꽤나 친절하게 설명이 있었다.
요약하자면 @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 프록시를 통해 호출을 가로채지 않는다.
'개발 > Spring' 카테고리의 다른 글
세션 인증 때 커스텀 애노테이션 적용하기 (0) 2023.06.26 Validation에서 에러 문구 설정 (0) 2023.06.20 컨트롤러(핸들러)가 조회되는 과정 (2) 2023.06.11 빈 스코프(Singleton, Prototype) (1) 2023.05.16 [AOP] before의 우선순위 (0) 2023.04.30