[Spring Basic] Singleton
클라이언트가 요청 할 때 마다 객체를 만들어서 반환하게 되면 메모리를 계속해서 낭비하게 되고, 심한 경우 서버가 터지는 경우도 발생한다.
공유해서 사용해도 괜찮은 객체는 하나만 생성하고 공유하도록 설계하는게 합리적이고, 이를 싱글톤 패턴이라고 부른다.
싱글톤 패턴을 사용하면 클래스의 인스턴스가 하나만 생성됨을 보장할 수 있다.
public class SingletonService {
private static final SingletonService instance = new SingletonService();
public static SingletonService getInstance(){
return instance;
}
private SingletonService(){
}
public void logic(){
System.out.println("싱글톤 로직 객체 호출됐음");
}
}
static으로 인스턴스를 하나 생성해서 올려놓는다.
외부에서 new를 통해 객체를 더 만드는걸 방지하기 위해 private생성자를 사용했고, 객체 인스턴스를 사용하려면 항상 같은 객체를 반환하는 getInstance()메서드를 호출해야 한다.
싱글톤 패턴을 사용해 메모리 낭비를 줄일 수 있는 점은 아주 훌륭하지만..
구현하는데 코드를 많이 작성해야하고, 객체지향설계의 원칙을 위반하는 등 여러 가지 문제점이 있다.
스프링 컨테이너는 싱글톤 패턴의 문제점을 모두 해결하면서 객체를 싱글톤으로 관리한다.
즉, 스프링 컨테이너는 싱글톤 컨테이너라고 부르고 이런 기능을 싱글톤 레지스트리라고 부른다.
한 개의 인스턴스가 여러 쓰레드에서 공유되기에 상태를 가지고 있도록 설계하는건 바람직하지 않다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService(){
return new MemberServiceImpl(memberRepository());
}
@Bean
public MemoryMemberRepository memberRepository() {
return new MemoryMemberRepository();
}
@Bean
public OrderService orderService(){
return new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy());
}
@Bean
public DiscountPolicy discountPolicy(){
// return new FixDiscountPolicy();
return new RateDiscountPolicy();
}
}
그런데 스프링은 어떻게 싱글톤을 유지하는걸까?
그런데 프린트로 로그를 찍어보면 알 수 있듯, 싱글톤을 유지하기 위해 객체의 생성은 한 번만 일어난다.
스프링은 클래스의 바이트코드를 조작하는 라이브러리를 사용해 싱글톤을 유지한다.
@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$$bd479d70
}
hello.core.AppConfig까지만 출력됨을 예상했지만, 뒤에 뭐가 더 붙어서 출력된다.
스프링 빈으로 등록할 때 내가 만든 클래스를 그대로 등록하는게 아니라, 스프링이 CGLIB 라는 바이트코드 조작 라이브러리를 사용해 임의로 다른 클래스를 만들고 그 클래스를 빈으로 등록한다.
바로 이 부분에서 싱글톤이 유지된다.
정확하게는 아니여도 CGLIB의 내부 로직을 대충 유추해 보면, 이미 컨테이너에 등록된 요소는 찾아서 반환하고 컨테이너에 등록되지 않은 요소는 기존 로직을 호출하는 방식대로 동작한다.
CGLIB가 적용된 클래스가 빈으로 등록된다.
새로 만들어진 클래스는 AppConfig의 자식 타입이므로 AppConfig타입으로 조회될 수 있다.
'Spring > Spring' 카테고리의 다른 글
[Spring Basic] 빈의 생명주기와 스코프 (0) | 2022.08.09 |
---|---|
[Spring Basic] 의존관계 주입 (0) | 2022.08.08 |
[Spring Basic] 스프링과 IoC (0) | 2022.08.06 |
[Spring Basic] JPA와 AOP (0) | 2022.07.29 |
[Spring Basic] 동기와 비동기 (0) | 2022.07.15 |
댓글
이 글 공유하기
다른 글
-
[Spring Basic] 빈의 생명주기와 스코프
[Spring Basic] 빈의 생명주기와 스코프
2022.08.09 -
[Spring Basic] 의존관계 주입
[Spring Basic] 의존관계 주입
2022.08.08 -
[Spring Basic] 스프링과 IoC
[Spring Basic] 스프링과 IoC
2022.08.06 -
[Spring Basic] JPA와 AOP
[Spring Basic] JPA와 AOP
2022.07.29