스프링 컨테이너는 등록된 빈의 싱글톤을 보장한다.

Web Development assistant·2022년 2월 23일
0

# spring

목록 보기
13/32
post-custom-banner

AppConfig.class

스프링 컨테이너의 환경설정을 다룬다. @Configuration

package hello.core;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import hello.core.discount.Discountpolicy;
import hello.core.discount.FixDiscountPolicy;
import hello.core.member.MemberRepository;
import hello.core.member.MemberService;
import hello.core.member.MemberServiceImpl;
import hello.core.member.MemoryMemberRepository;
import hello.core.order.OrderService;
import hello.core.order.OrderServiceImpl;

@Configuration
public class AppConfig {
	private int number = 0;
	@Bean
	public MemberService memberService() {
		number ++;
		System.out.println("call memberService");
		System.out.println(number);
		return new MemberServiceImpl(memberRepository());
	}

	@Bean
	public MemberRepository memberRepository() {
		number ++;
		System.out.println("call memberRepository");
		System.out.println(number);
		return new MemoryMemberRepository();
	}

	@Bean
	public OrderService orderService() {
		number ++;
		System.out.println("call orderService");
		System.out.println(number);
		return new OrderServiceImpl(memberRepository(), discountpolicy());
	}

	@Bean
	public Discountpolicy discountpolicy() {
		// return new RateDiscountPolicy();
		return new FixDiscountPolicy();
	}
}

위의 소스에서 주목해야할 점
MemberServiceImpl, OrderServiceImpl, MemberRepository 객체는
각각 return new MemoryMemberRepository()를 리턴하고 있다.

허나 MemberRepository는 단 한 번만 호출되는데
즉 new MemoryMemberRepository()가 1번만 생성되는것이고
싱글톤을 유지한다는 점.

비밀은 스프링의 @Configuration 어노테이션..

AppConfigTest

	@Test
	public void AppConfigTest() {
		ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
		
		AppConfig bean = ac.getBean(AppConfig.class);
		MemberServiceImpl memberService = ac.getBean("memberService", MemberServiceImpl.class);
		
		
		System.out.println("AppConfig 클래스 네임 : "+ bean.getClass()); // class hello.core.AppConfig$$EnhancerBySpringCGLIB$$989baddf
		System.out.println("memberService 클래스 네임 : "+ memberService.getClass()); // class hello.core.member.MemberServiceImpl
	}

위의 예제를 돌리면
Appconfig 빈의 클래스명 뒤에

'$$EnhancerBySpringCGLIB$$989baddf' 가 추가된 걸 확인 할 수 있다.

이는 스프링이 CGLIB라이브러리라는 바이트코드 조작 라이브러리를 사용해서 Appconfig 클래스를 상속받은 임의의 다른 클래스를 만들고,
그 다른 클래스를 스프 빈으로 등록한것.
그 임의의 다른 Appconfig 클래스가 싱글톤이 되도록 보장해주는것이다.

@Bean이 붙은 메서드마다 이미 스프링 빈이 존재하면
존재하는 빈을 반환하고, 없으면 새로 생성해서 스프링 빈을 등록 하고 반환한다.
그 덕분에 스프링컨테이너의 빈들은 싱글톤이 보장된다.

@Configuration 를 주석처리하게되고 실행한다면??

Appconfig 빈의 클래스명 뒤의 $$EnhancerBySpringCGLIB~ 는
사라지게 되고,
@@impl 클래스들이 실행할때 마다 새로운 객체를 생성하게되며,
싱글톤은 깨지게 된다.

그래서 스프링 설정 정보는 항상 @Configuration 사용해라.

추가적으로 스프링 빈들은 stateless를 보장해야한다.

post-custom-banner

0개의 댓글