스프링 컨테이너 : BeanFactory와 그를 상속 받는 ApplicaionContext
ApplicationContext : BeanFactory 인터페이스를 상속 받는 인터페이스, 빈 관리 기능 + 편리 부가 기능
public interface ApplicationContext
extends EnvironmentCapable
, ListableBeanFactory
, HierarchicalBeanFactory
, MessageSource
, ApplicationEventPublisher
, ResourcePatternResolver {
@Nullable
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
BeanFactory만으로 부족한 부가기능을 제공
EnvironmentCapable | 환경설정 |
ListableBeanFactory | |
HierarchicalBeanFactory | |
MessageSource | 메세지 소스를 활용한 국제화 기능 |
ApplicationEventPublisher | 애플리케이션 이벤트 (이벤트 발행, 구독 모델 지원) |
ResourcePatternResolver | 편리한 리소스 조회 : 파일, 클래스패스, 외부 등 리소스를 조 |
BeanDefinition - 스프링 빈 설정 메타 정보
설정 형식이 다양 = 스프링 컨테이너는 빈 생성관련하여 자바 코드로 할지, XML할지 몰라도 몰라도 BeanDefinition만 알면 된다 (역할과 구현을 개념적으로 나눈 것)
스프링 컨테이너는 BeanDefinition만 의존한다
아래 필드를 이용하여, 설정 정보를 읽고, BeanDefinition에서 빈 메타 정보를 생성
private final AnnotatedBeanDefinitionReader reader;
결론은 스프링이 다양한 형태의 설정 정보를 BeanDefinition으로 추상화해서 사용하는 것 정도만 이해하면 충분하다.
싱글톤 컨테이너
싱글톤 구현
(private 객체생성하여 메서드 영역에 올리기 -> 해당 객체를 호출하는 public static 메서드 생성 -> 외부 생성자 호출 막기)
public class SingleTonService {
// 1. static 영역에 객체를 딱 1개만 생성해둔다.
private static final SingleTonService instance = new SingleTonService();
// 2. public 으로 열어서 객체 인스턴스가 필요하면 이 static 메서드를 통해서만 조회하도록 허용한다.
public static SingleTonService getInstance() {
return instance;
}
// 3. 생성자를 private으로 선언해서 외부에서 new 키워드를 사용한 객체 생성을 못하게 막는다.
private SingleTonService() {}
public void logic() {
System.out.println("싱글톤 객체 로직 호출");
}
}
문제점
- 외부에서 객체를 호출할때 getInstance()로 호출 해야한다 : 클라이언트가 구체 클래스에 의존 → DIP위반 + OCP 위반 가능성이 높다
- 테스트 어려움, 유연성 떨어짐
- private 생성자로 자식 클래스 만들기 어려움
싱글톤 컨테이너(스프링 컨테이너)
스프링컨테이너는 위 문제점을 해결하면서, 싱글톤으로 객체를 관리한다.
@Bean 으로 스프링컨테이너의 스프링 빈 저장소에 '빈 이름'과 '빈 객체' 를 등록(생성)하고, 호출할때마다 저장된 빈 객체를 반환하는 식으로 하나의 객체만 관리한다.
※ 이렇게 싱글톤 객체를 생성하고 관리하는 기능을 싱글톤 레지스트리라고 한다.
주의점
여러 클라이언트가 하나의 객체를 이용하므로 stateless로 설계해야한다.
멀티스레드 환경에서 작업간 stateful field의 값이 공유가 되기 때문!!
- 외부에서 값을 변경할 수 있는 필드가 있으면 안되고,
- 읽기 전용인게 좋고
- 특정 클라이언트에 의존적인 필드가 있으면 안된다
- 필드 대신, 자바에서 공유되지 않는 지역변수, ThreadLocal 등을 사용해야 한다.
@Configuration 과 바이트코드 조작
빈 저장소에 "다른 빈 이름/같은 타입의 빈 객체"를 등록할 경우
생성자 호출시, new 연산자를 두번 이상 쓰더라도, @Bean 대상이라면 인스턴스가 하나만 들어간다.
스프링 컨테이너는 싱글톤 레지스트리이므로, 스프링 빈이 싱글톤이 되도록 보장되기 때문이다.
이는 스프링이 클래스의 바이트코드를 조작하는 라이브러리를 사용하였기 때문
※ @Configuration 는 스프링이 CGHLIB 라이브러리를 사용하여, 해당 클래스를 상속받은 임의의 다른 클래스를 만들고, 그 다른 클래스( AppConfig$$SpringCGLIB$$)를 스프링 빈으로 등록한다.
@Test
void configurationDeep() {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
AppConfig bean = ac.getBean(AppConfig.class);
System.out.println("bean.getClass() = " + bean.getClass());
// bean.getClass() = class hello.core.AppConfig$$SpringCGLIB$$0
}
※ AppConfig : @Configuration 선언된 클래스
등록된 클래스는 인스턴스가 이미 스프링 컨테이너에 있으면, 스프링 컨테이너에 찾아서 반환토록하고, ,없으면 기존 로직을 호출해서 빈객체를 생성하고 스프링 컨테이너에 등록하는 동적인 코드로 구성
해당 클래스로 싱글톤이 어느 상황에서든 보장이 된다.
※ @Configuration을 사용치 않고 @Bean 을 사용해도 레지스트리에 등록은 되지만, 싱글톤은 보장되지 않는다.
스프링 핵심 원리 - 기본편 강의 | 김영한 - 인프런
김영한 | 스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보
www.inflearn.com
'SPRING' 카테고리의 다른 글
AOP (작성중) (0) | 2025.01.31 |
---|---|
Entity·DTO·VO와 사용범위, 변환방법 (0) | 2025.01.11 |
Spring Bean과 빈 조회하기 (0) | 2024.12.25 |
ApplicationContext(스프링 컨테이너)가 작동하는 과정 (0) | 2024.12.22 |
IoC, DI와 컨테이너 (0) | 2024.12.22 |