스프링 컨테이너에 빈(Bean)을 등록하면 기본적으로 싱글톤 패턴으로 빈을 관리하게 된다. 따라서 해당 빈을 요청하게 되면 항상 동일한 빈을 반환해주는 것을 확인할 수 있다.
물론 기본 빈 등록 방식이 싱글톤 방식이라는 의미이며, 요청할 때마다 새로운 객체를 생성하여 반환해주는 프로토타입 방식 등 빈 스코프에 따라 다른 방식도 제공한다.
싱글톤 패턴이란 클래스의 인스턴스가 1개만 생성됨을 보장해주는 디자인 패턴으로 해당 인스턴스를 공유하여 사용함으로써 메모리를 절약할 수 있는 장점이 있다.
싱글톤 패턴에 대해서 공부하고 싶다면 다음 글들을 참고하길 바란다.
https://sorjfkrh5078.tistory.com/107?category=1007502
https://sorjfkrh5078.tistory.com/108?category=1007499
그렇다면 간단한 테스트를 통해 정말로 동일한 빈을 반환해주는지 알아보자.
MyBean이라는 클래스를 하나 선언해주고 이를 AppConfig 클래스에서 빈으로 등록해주도록 설정해주자.
public class MyBean {
}
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
테스트를 해보면 단순히 AppConfig를 통해 MyBean을 호출하면 다른 빈이 조회되지만, 스프링 컨테이너에 등록한 다음 MyBean을 호출하면 싱글톤 방식으로 동일한 빈이 조회되는 것을 확인할 수 있다.
@SpringBootTest
class SingletonContainerTest {
@Test
@DisplayName("싱글톤 컨테이너 : 동일한 빈 반환")
void test() {
AppConfig appConfig = new AppConfig();
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
assertThat(appConfig.myBean()).isNotSameAs(appConfig.myBean());
System.out.println("MyBean = " + appConfig.myBean());
System.out.println("MyBean = " + appConfig.myBean());
assertThat(ac.getBean(MyBean.class)).isSameAs(ac.getBean(MyBean.class));
System.out.println("MyBean = " + ac.getBean(MyBean.class));
System.out.println("MyBean = " + ac.getBean(MyBean.class));
}
}
이처럼 스프링 컨테이너는 싱글톤을 보장해주기 때문에 싱글톤 컨테이너라고도 불린다.
또한, 우리는 싱글톤 패턴을 위한 코드를 작성하지 않아도 스프링 프레임워크가 알아서 싱글톤 패턴을 적용해주기 때문에 굉장히 편리한 장점이 있다.
그렇다면 Java 코드에는 싱글톤 패턴을 위한 아무런 코드가 존재하지 않음에도 불구하고 스프링 프레임워크는 어떻게 빈들을 싱글톤 패턴으로 관리해줄 수 있는 것일까?
이는 CGLIB라는 바이트코드 조작 라이브러리를 사용하여 가능하게 해준다.
스프링 프레임워크는 @Configuration 어노테이션이 달린 클래스에 속한 @Bean들을 스프링 컨테이너에 등록할 때 해당 클래스의 빈들에게 싱글톤 패턴을 적용하기 위해 임의의 다른 클래스를 만들어서 스프링 빈으로 등록한다.
CGLIB의 내부 기술은 굉장히 복잡하지만 대충 다음과 같은 로직으로 싱글톤 패턴을 적용해준다고 예상할 수 있다.
@Bean
public MyBean myBean() {
if (myBean이 이미 스프링 컨테이너에 등록되어 있으면?) {
return 스프링 컨테이너에서 찾아서 반환;
} else { //스프링 컨테이너에 없으면
기존 로직을 호출해서 MyBean를 생성하고 스프링 컨테이너에 등록
return 반환
}
}
이를 통해 스프링 컨테이너는 싱글톤을 보장해주는 것이다.
실제로 스프링 컨테이너에 등록한 AppConfig 클래스를 조회해보면 순수한 클래스가 아닌 CGLIB가 붙은 클래스가 조회되는 것을 확인할 수 있다.
@SpringBootTest
class SingletonContainerTest {
@Test
@DisplayName("싱글톤 컨테이너 : 동일한 빈 반환")
void test() {
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("AppConfig = " + ac.getBean(AppConfig.class));
}
}
주의해야 할 점은 반드시 @Configuration 어노테이션이 존재해야 한다는 것이다.
스프링 프레임워크는 스프링 빈을 등록할 때 @Configuration 어노테이션이 붙은 빈들만 CGLIB를 적용하여 싱글톤을 보장해준다.
@Bean만 사용해도 스프링 빈으로 등록되지만, 의존관계 주입이 필요해서 메서드를 직접 호출하는 경우에는 싱글톤을 보장해주지 않는다.
[ Reference ]
'IT 개인 공부 > Spring' 카테고리의 다른 글
[Spring] HTTP 메시지 컨버터 (0) | 2021.09.03 |
---|---|
[Spring] 빈 스코프(Scope) 종류 (0) | 2021.08.23 |
[Spring] 조회한 빈(Bean)이 모두 필요할때 처리하는 방법 (0) | 2021.08.19 |
[Spring] 조회 빈(Bean)이 2개 이상일때 처리하는 방법 (0) | 2021.08.18 |
[Spring] Bean & DI & IoC 컨테이너 (0) | 2021.08.13 |
댓글