웹 애플리케이션은 보통 여러 고객이 동시에 요청한다.
스프링 없는 순수한 DI 컨테이너인 AppConfig를 사용한다 했을 때
// static영역에 1개만 생성
private static final SingletonService instance = new SingletonService();
// 해당 메소드로 객체 인스턴스 사용 -> 싱글톤
public static SingletonService getInstance() {
return instance;
}
// 생성자 private로 방지
private SingletonService() {
}
고객의 요청이 올 때 마다 객체 생성이 아닌 만들어진 객체를 공유, 효율적으로 사용
스프링 컨테이너: 싱글톤 패턴의 문제점 해결 및 객체 인스턴스를 싱글톤으로 관리
싱글턴 패턴을 적용하지 않아도, 객체 인스턴스를 싱글톤으로 관리
싱글톤 컨테이너 역할 수행
이런 기능 덕분에 싱글톤 패턴의 모든 단점을 해결 및 객체를 싱글톤으로 유지
싱글톤 패턴을 위한 지저분한 코드 X
DIP, OCP, 테스트, private 생성자로 부터 자유롭게 싱글톤 사용가능
ApplicationContext ac = new
AnnotationConfigApplicationContext(AppConfig.class);
Menu menu1 =ac.getBean("Menu", Menu.class);
Menu menu2 =ac.getBean("Menu", Menu.class);
// menu1 == menu2
assertThat(menu1).isSameAs(menu2);
테스트 코드에서 Assertions 사용한다.
jnuit 과 assertj 가 있다.
스프링의 기본 빈 등록 방식은 싱글톤 이지만 다른 방식도 지원한다.
ex) 프로토 타입 (요청할때마다 새로운 객체 반환)
히나의 객체 인스턴스를 공유하기 떄문에 싱글톤 객체는 무상태 설계 해야한다.
특정 클라이언트에 의존적인 필드가 없어야한다.
특정 클라이언트가 값을 변경할 수 있는 필드가 없어야 한다.
가급적 읽기만 가능해야한다.
필드 대신에 자바에서 공유되지 않는, 지역변수, 파라미터, ThreadLocal등을 사용해야 한다.
스프링 빈의 필드에 공유 값을 설정하면 큰 장애가 발생할 수 있다.
스프링 빈은 항상 무상태 설계를 기억하자
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberServiceImpl(memberRepository());
}
@Bean
public OrderService orderService() {
return new OrderServiceImpl(memberRepository(),discountPolicy());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
...
}
여기서 보면 memberRepository()를 MemberService에서 1번 OrderService에서 1번씩 총 2번 호출하여 MemoryMemberRepository객체가 2개 생긴거 아닌가 싶다.
하지만 @Configuration
의 기능으로 싱글톤이 유지된다.
스프링 컨테이너는 스프링 빈이 싱글톤이 되도록 보장해야한다.
스프링은 자바 코드까지는 건드릴 수 없어서
스프링 클래스의 바이트 코드를 조작하는 라이브러리를 사용한다.
@Configuration
이 핵심이다.
여기서 AppConfig 스프링 빈을 조회해서 클래스 정보를 출력해보면
@Test
void configurationDeep() {
ApplicationContext ac = new
AnnotationConfigApplicationContext(AppConfig.class);
//AppConfig도 스프링 빈으로 등록된다.
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean = " + bean.getClass());
}
출력결과
bean = class hello.core.AppConfig$$EnhancerBySpringCGLIB$$bd312d65
스프링이
CGLIB
라는 바이트 코드 조작 라이브러리를 사용해서
AppConfig 클래스를 상속받은 임의의 다른 클래스를 만들고
그 클래스를 스프링 빈으로 동록한다.
@Bean
이 붙은 메서드마다 스프링 빈이 존재하면 존재하는 빈 반환
빈이 없으면 생성해서 스프링 빈으로 등록 후 반환 하는 코드가 동적으로 생성됨
덕분에 싱글톤이 보장
결과적으로는 바이트 코드 조작 라이브러리가 작동하지 않고
요청하는 대로 객체가 생성되어 싱글톤이 파괴된다.
@Bean
만 사용시 스프링 빈 등록은 되지만, 싱글톤 보장 X- 스프링 설정 정보는 항상
@Configuration
을 사용하자!
🔖 학습내용 출처