스프링 & 싱글톤 컨테이너

이정원·2024년 10월 22일

1.ApplicationContext

ApplicationContext은 스프링 컨테이너이다.

ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

스프링 컨테이너를 생성할때 구성 정보를 지정하고(AppConfig.class) 해당 설정 파일의 @Bean 애노테이션을 확인하여 빈 등록, 의존 관계 설정을 자동으로 처리한다.


빈 조회 메서드:

  • ac.getBean(빈이름(ex:"memberService"),타입(ex:MemberService.class))
  • ac.getBean(타입)

조회 -상속관계:
부모 타입으로 조회하면, 자식 타입도 함께 조회한다. 그래서 모든 자바 객체 최고 부모인 Object 타입으로 조회하면, 모든 스프링 빈을 조회한다.


BeanFactory와 ApplicationContext

BeanFactory

  • 스프링 컨테이너의 최상위 인터페이스다.
  • 스프링 빈을 관리하고 조회하는 역할을 담당한다.
  • getBean() 을 제공한다.

ApplicationContext

  • BeanFactory 기능을 모두 상속받아서 제공한다.
  • BeanFactory 기능외에 애플리케이션 개발에 많은 부가 기능(메세지 국제화,환경변수,이벤트,리소스 조회)을 제공한다.

BeanFactory를 직접 사용할 일은 거의 없다. 부가기능이 포함된 ApplicationContext를 사용한다. 이 밖에도 다양한 형식의 설정 정보(JAVA,XML etc..)를 받을수 있다.

스프링 빈 설정 메타 정보 - BeanDefinition
다양한 설정 형식을 지원하는 밑바탕에는 @Bean 애노테이션을 통해 각각 하나씩 메타정보가 생성되며,이 메타 정보(클래스 타입, 스코프, 의존성)는 스프링 컨테이너가 빈을 관리하기 위해 사용하는 BeanDefinition 객체로 표현된다.

실무에서 직접 BeanDefinition을 다룰 필요는 거의 없지만, 스프링 컨테이너가 내부적으로 이 메타 정보를 사용해 빈을 관리한다는 점을 이해하는 것이 중요하다.

2.Singleton Container

스프링은 기업용 온라인 서비스 기술을 지원하기 위해 태생적으로 개발되었으며, 일반적으로 여러 고객이 동시에 요청하는 환경에서 사용된다. 이전에 순수한 자바 코드로 작성한 DI 컨테이너인 AppConfig는 매 요청마다 새로운 객체를 생성한다. 그러나 이 방식은 고객 트래픽이 많을수록 메모리 낭비가 심해질 수 있다.

이 문제를 해결하기 위해, 객체를 매번 새로 생성하는 대신 딱 1개의 객체만 생성하고 이를 여러 요청에서 공유하는 방식이 필요하다. 이를 구현하는 것이 바로 싱글톤 패턴이다. 싱글톤 패턴은 애플리케이션 내에서 하나의 객체만을 생성하고, 해당 객체를 모든 요청이 공유하도록 하는 설계 방식이다.

순수 자바 코드 구현:

//1. static 영역에 객체를 딱 1개만 생성해둔다.
 private static final SingletonService instance = new SingletonService();
 
 //2. public으로 열어서 객체 인스턴스가 필요하면 이 static 메서드를 통해서만 조회하도록 허용한.
 public static SingletonService getInstance() {
 return instance;
 }
 
 //3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다.
 private SingletonService() {
 }

해당 코드의 문제점은,

1.코드 복잡성: 싱글톤 패턴을 구현하는 데 필요한 코드가 많아진다. 특히, 객체의 생성과 관리 책임을 직접 구현해야 하며, 이를 수정하거나 확장하려면 코드 변경이 불가피하다.

2.의존관계 문제: 클라이언트가 구체 클래스에 의존하게 되어, DIP(의존성 역전 원칙)와 OCP(개방/폐쇄 원칙)를 위반할 가능성이 크다. 이는 코드의 유연성과 유지보수성을 떨어뜨린다.

하지만, 스프링 컨테이너는 기본적으로 빈을 싱글톤으로 관리한다. 즉, @Bean 또는 @Component로 등록된 스프링 빈은 특별한 설정이 없는 한 하나의 객체만 생성되며, 이를 모든 요청이 공유하게 된다.

주의) 여러 클라이언트가 하나의 같은 객체 인스턴스를 공유하기 때문에 싱글톤 객체는 상태를 유지하게 설계되면 안된다.(동시성 문제)

@Configuration과 바이트코드 조작

만약 설정 파일에서 빈으로 등록한 각각의 메서드에서 동일한 객체를 생성한다면 여러개의 동일한 객체가 생성될까? -> 아니다, 스프링은 순수한 자바 코드 단에서의 싱글톤을 지키기 위해 CGLIB라는 바이트코드 조작 라이브러리를 사용해서 프록시 객체가 등록되어 이미 생성된 빈을 반환하게 된다.

주의)@Configuration 설정 정보가 빠지면 싱글톤을 보장하지 못한다.

0개의 댓글