[섹션 5. 싱글톤 컨테이너] @Configuration과 바이트코드 조작의 마법 / 인프런 김영한 스프링 핵심 원리 기본편
이번 시간에는 @Configuration과 순수한 자바코드와는 다른 바이트코드 조작에 대해서 알아보았다.
스프링 컨테이너는 싱글톤 레지스트리이다. 그렇기 때문에 스프링 빈이 싱글톤이 되도록 보장을 해주어야 한다.
하지만, 스프링이 자바 코드까지 건드려서 싱글톤을 보장하기는 어렵다.
지난 시간에 다뤘던 AppConfig에서 등록된 빈 객체를 여러번 호출했는데도,
실제 로그를 찍어보니 싱글톤을 보장하며 한번만 호출되었던 것이 어떻게 된 것인지 직접 꺼내보면서 알아보려고 한다.
테스트 코드를 작성해준다.
new AnnotationConfigApplicationContext(AppConfig.class) 를 하면 스프링 빈으로 등록이 되고, getBean이 가능하다.
그렇게 테스트를 꺼내보면 클래스 위치와 달러표시 뒤에 EnhancerBySpringCGLIB가 되어있는 것을 볼 수 있다.
순수한 클래스라면 AppConfig까지 클래스 위치까지만 출력 됐을 것이다.
하지만 뒤에 CGLIB이 붙으면서 다르게 출력이 된다.
이것은 내가 만든 클래스가 아닌, 스프링이 CGLIB이라는 바이트코드 조작 라이브러리를 사용해서 AppConfig 클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스를 스프링 빈으로 등록한 것이다.
다시 말해, AppConfig가 있고 CGLIB이라는 바이트코드 조작 라이브러리를 통해서 AppConfig를 상속받은 다른 클래스를 만든다. 그러고는 스프링은 AppConfig가 아닌 상속받은 @CGLIB 클래스를 스프링 빈으로 등록을 한다.
그 상속받은 클래스가 바로 싱글톤이 보장되도록 해준다.
그래서 이미 스프링 컨테이너에 등록되어 있는 빈 객체가 호출요청이 들어오면,
스프링 컨테이너에서 찾아서 반환한다.
스프링 컨테이너에 없다면, 기존 로직을 호출해서 객체를 생성하고 컨테이너에 등록을 하고 반환해준다.
이런 코드가 동적으로 만들어지면서 싱글톤이 보장되는 것이다.
참고로 AppConfig@CGLIB은 AppConfig의 자식 타입이므로, AppConfig 타입으로 조회할 수 있다.
추가적으로, AppConfig 클래스에 @Configuration을 주석처리하고 조회하니,
CGLIB이 아닌 순수한 클래스가 조회가 되는것을 확인할 수 있다.
하지만 @Configuration을 주석처리 하게 되면, 빈 객체를 호출할 때 마다 계속 생성해서 반환해주니,
싱글톤이 깨지게 된다.
정리를 해보자면, @Bean만 사용해도 스프링 빈으로 등록이 되지만, 싱글톤을 보장하지 않는다.
고민할 것 없이 스프링 설정 정보는 @Configuration을 사용하면 된다!