0. 스프링 컨테이너
- ApplicationContext를 스프링 컨테이너라고 부른다.
- 기존엔 개발자가 AppConfig에서 직접 객체를 생성하고, 의존관계를 정의했지만 스프링 컨테이너를 이용하면 편리해진다.
- 스프링 컨테이너에서 @Configuration가 붙은 설정을 찾아서, 해당 설정 정보를 이용해서 빈과, 의존 관계를 구성한다.
- @Bean이 붙은 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다.
1. 스프링 컨테이너 생성
//스프링 컨테이너 생성
ApplicationContext applicationContext =
new
AnnotationConfigApplicationContext(AppConfig.class)
2. 이후 AppConfig 클래스 안의 @Bean 메서드를 호출하면서 반환된 객체를 스프링 빈으로 등록
- 빈의 이름은 해당 메서드 이름의 앞글자를 소문자로 사용하여 등록된다.
3. 스프링 컨테이너에 빈이 등록되고, 의존 관계가 주입된다.
- 이렇게 자바 코드(AppConfig.class)를 이용해서 스프링 컨테이너를 구성할 경우 생성자가 실행되면서 동시에 의존 관계가 설정된다.
1. 싱글톤
스프링 컨테이너인 ApplicationContext를 사용하지 않고 그냥 AppConfig.class를 정의해서 직접 의존관계를 주입했더라면 매번 호출마다 새로운 객체가 생성될 것이다.
하지만 스프링 컨테이너는 등록된 스프링 빈을 싱글톤으로 관리한다.
주의점 : 스프링 컨테이너의 싱글톤은 항상 무상태(stateless)로 설계해야 한다.
만약 수정에 이용하는 공유 변수가 있다면 싱글톤 객체이므로 필드 값이 연결 상태(stateful)가 돼버린다.
tempA = applicationContext.getBean("service");
tempB = applicationContext.getBean("service");
// 스프링 컨테이너에서의 빈 조회는 getBean("빈 이름")으로 조회가 가능하다.
이후에
tempA.buy("10000"); // tempA는 만원 구매
tempB.buy("20000"); // tempB는 2만원 구매
tempA.getPrice(); // A의 기댓값은 만원이다. 하지만 공유 필드로 2만원이 조회된다.
위와 같이, 싱글톤으로 객체가 관리되기 때문에 필드라 공유돼버린다.
따라서 A가 만원을 사용했지만, B에서 2만 원으로 필드 값이 set 되었고 최종적으로 A가 자신이 쓴 금액을 조회할 때 이미 변경돼버린 2만 원이 반환된다.
2. 어떻게 싱글톤으로 컨테이너를 유지할까?
결과부터 말하자면 @Configuration 어노테이션에 의해서 싱글톤이 된다.
만약 AppConfig에 @Configuration을 붙이지 않고 설정 정보로 등록하면 싱글톤이 보장되지 않는다.
AppConfig.class도 역시 스프링 빈으로 등록이 되는데,
getBean("Appconfig.class")
를 통해 클래스 정보를 확인해보면, class AppConfig$$EnhancerBySpringCGLIB$$bd479d70 로 확인이 된다.
원래 클래스 정보를 조회하면 class AppConfig로 조회돼야 할 텐데 뒤에 CGLIB으로 조작이 되어있다.
이것은 바로 내가 만든 클래스가 아니라 스프링에서 CGLIB이라는 바이트 조작 라이브러리를 이용해서 AppConfig 클래스를 상속받은 임의의 조작 클래스를 만들어 낸 것이다. 그리고 그 조작 클래스를 스프링 빈에 등록한 것이다.
CGLIB의 내부 기술은 매우 복잡해서, 분석하기 힘들지만 아마도 간단하게 유추해보자면
@Bean의 메서드에
이미 컨테이너에 등록되어 있으면 새로 객체를 만들지 않고, 없다면 새 객체를 만들어서 반환하는 로직
이 조작되어 있지 않을까 싶다.
따라서 @Configuration을 붙이지 않으면 @Bean으로 된 메서드는 등록이 되지만 싱글톤이 보장이 되지 않는다.
그냥 @Configuration 붙여서 사용하면 되겠다.
'개발 공부 > 스프링' 카테고리의 다른 글
스프링 - 의존 관계 주입 방법 4가지 (0) | 2021.09.17 |
---|---|
스프링 - @Component와 컴포넌트 스캔 (0) | 2021.09.17 |
스프링 - 의존 관계와 DI, Ioc 컨테이너 (0) | 2021.09.16 |
스프링 MVC - 서블릿을 통한 HTTP 요청(GET, POST, API, JSON) (0) | 2021.09.08 |
스프링 MVC - 웹 구조, 서블릿 (0) | 2021.09.04 |