스프링은 기본적으로 별다른 설정을 하지 않으면 내부에서 생성하는 빈 오브젝트를 모두 싱글톤으로 만든다.
스프링은 서버 환경에서 싱글톤이 만들어져 서비스 오브젝트 방식으로 사용되는 것은 적극 지지한다. 하지만 자바의 기본적인 싱글톤 패턴의 구현 방식은 여러가지 단점이 있기때문에 스프링은 직접 싱글톤 형태의 오브젝트를 만들고 관리하는 기능을 제공한다.
스프링 컨테이너는 싱글톤 컨테이너 역할을 하며, 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 Singleton Registry라고 한다.
Singleton Registry의 장점은 평범한 자바 클래스이더라도 IoC방식의 컨테이너를 사용해 생성과 관계설정, 사용 등에 대한 제어권을 손쉽게 싱글톤 방식으로 만들어져 관리되게 할 수 있다. 그렇기 때문에 테스트 환경에서도 자유롭게 오브젝트를 만들 수 있고, 테스트를 위한 목적으로 오브젝트를 대체하는 것도 간단하다.
즉, 싱글턴 패턴의 단점을 해결하면서 객체를 싱글톤 방식으로 유지 할 수 있다.
( 1. 싱글톤 패턴을 위한 지저분한 코드가 추가되지 않음. 2. DIP, OCP, 테스트, private 생성자로 부터 자유롭게 싱글톤 사용 가능)
싱글톤이 멀티스레드 환경에서 서비스 형태의 오브젝트로 사용되는 경우에는 stateless 방식으로 만들어져야한다. 이때는 읽기전용 값이라면 초기화 시점에 인스턴스 변수에 저장해두고 공유하는 것은 문제 없다. 만약 각 요청에 대한 정보나, DB 서버의 리소스로 부터 생성한 정보는 파라미터와 로컬 변수, 리턴 값을 이용하면 된다. 메소드 파라미터나, 메소드 안에서 생성되는 로컬 변수는 매번 새로운 값을 저장할 독립적인 공간이 만들어지기 때문에 싱글톤이라고 해도 문제없다.
Spring에서의 Singleton Pattern
spring의 bean들은 Bean Factory에 의해서 관리되고 있으며, 기본적으로 이러한 bean의 생명주기의 scope는 singleton을 따르고 있다. Spring Boot에서는 별도의 설정이 없다면, DefaultListableBeanFactory를 기본으로 사용하며, resolveBean 메소드를 보면 알 수 있다.
순수한 클래스라면 class dh0023.springcore.config.AppConfig로 출력되어야한다. 하지만, @Configuration 이 CGLIB 바이트 코드 조작 라이브러리를 사용해 AppConfig 를 상속받은 임의의 클래스(AppConfig@CGLIB)를 스프링 빈으로 등록한다.
@Bean이 붙은 메서드마다 이미 스프링 빈이 존재한다면, 존재하는 빈을 반환하고, 존재하지 않는다면 새로 생성하는 로직이 포함되어 있을 것으로 예상된다.
만약 @Configuration 을 설정하지 않고 @Bean 빈을 등록하면 어떻게 될까?
/** * 애플리케션의 실제 동작에 필요한 구현 객체 생성 * 생성한 객체 인스턴스의 참조를 생성자를 통해 주입해준다. * @Configuration 어노테이션으로 @Bean이 싱글톤으로 관리될 수 있게 해준다. */publicclassAppConfig { @BeanpublicMemberServicememberService() {System.out.println("call AppConfig.memberService");returnnewMemberServiceImpl(memberRepository()); } @BeanpublicMemberRepositorymemberRepository() {System.out.println("AppConfig.memberRepository");returnnewMemoryMemberRepository(); } @BeanpublicOrderServiceorderService(){System.out.println("AppConfig.orderService");returnnewOrderServiceImpl(memberRepository(), getDiscountPolicy()); } @BeanpublicDiscountPolicygetDiscountPolicy() {returnnewRateDiscountPolicy(); }}