스프링 컨테이너(Spring Container)

김나우·2023년 6월 26일
0

Spring

목록 보기
13/13

스프링 컨테이너(Spring Container)


스프링 컨테이너는 스프링 프레임워크의 핵심 컴포넌트이다.

스프링 컨테이너는 자바 객체의 생명 주기(Life Cycle)를 관리하며, 생성된 자바 객체들에게 추가적인 기능을 제공한다.
스프링에서는 자바 객체를 빈(Bean) 이라 한다. IoC와 DI의 원리가 이 스프링 컨테이너에 적용된다.

개발자는 new 연산자, 인터페이스 호출, 팩토리 호출 방식 등으로 객체를 생성하고 소멸시킬 수 있는데,
스프링 컨테이너가 이 역할을 대신해 준다.

즉, 제어의 흐름을 외부에서 관리하는 것이다.

스프링 컨테이너의 종류


위 그림은 ApplicationContext 인터페이스가 다른 인터페이스들을 다중 상속하고 있는 모습이다.

MessageSource : 다국어 메시지 처리 기능 제공
EnvironmentCapable : 프로파일 기능, 프로퍼티 기능들을 제공
BeanFactory : 스프링 빈을 관리하고 조회하는 역할
ApplicationEventPublisher : 이벤트 기반의 프로그래밍을 할 때 필요한 기능 제공
ResourceLoader : 리소스를 읽어오는 기능 제공

그림에서 확인할 수 있듯이 ApplicationContext 는 다중상속하고 있는 기능들을 다 가지고 있는 것이다.
BeanFactory기능을 모두 상속해 Bean 객체를 관리하며, 메시지 처리, 리소스, 이벤트와 관련된 기능을 추가적으로 가지고 있는 인터페이스다

그렇다면 왜 Bean의 생명주기를 관리해주는 BeanFactory가 있는데 똑같은 기능을 제공하는 ApplicationContext 가 또 있을까?

ApplicationContext


ApplicationContext를 더 많이 사용하는 이유는 애플리케이션을 개발할 때는 빈 관리, 조회하는 기능 외에 수 많은 부가 기능이 필요하기 때문이다.

특징

  1. 빈의 미리 로딩(Pre-loading)
    스프링 컨테이너가 시작될 때 빈을 미리 로딩한다.
    따라서 애플리케이션 시작 시점에 필요한 빈들을 미리 인스턴스화 하고 구성할 수 있다.
    이는 애플리케이션 시작 시간을 단축시키고 사용자들에게 더 나은 응답성을 제공한다.

  2. 자동 와이어링(Automatic Wiring)
    빈 간의 의존성을 자동으로 주입하는 자동 와이어링(Automatic Wiring)기능을 제공한다.
    이를 통해 개발자가 명시적으로 의존성을 설정하지 않아도 스프링이 자동으로 빈들을 연결해준다.

  3. AOP(Aspect-Oriented Programming)지원
    AOP를 지원하기 위한 기능을 제공한다.
    AOP는 핵심 비즈니스 로직과 각각의 관점(Aspect)를 분리하여 모듈화할 수 있는 기술이다.
    AOP를 쉽게 적용할 수 있도록 지원하고, 관점과 핵심 비즈니스 로직사이의 연결을 자동으로 처리할 수 있다.

  4. 국제화(i18n)지원
    국제화(i18n)와 지역화(l10n)을 지원한다.
    다국어 지원과 메세지 리소스 처리를 위한 통합된 방식을 지원

  5. 이벤트 발행 및 처리
    애플리케이션 내에서 이벤트 발행 및 처리를 지원한다.
    이벤트 기반 아키텍쳐를 사용하여 애플리케이션 컴포넌트 간의 통신느슨한 결합을 촉진할 수 있다

동작 방식

  1. 빈의 정의 및 설정 로딩
    설정메타데이터(예:XML파일)를 로딩하여 빈의 정의를 파악한다.
    설정 메타이데터에는 빈의 클래스, 의존성, 초기화 방법 등을 포함한다

  2. 빈의 인스턴스화 및 초기화
    ApplicationContext는 빈의 인스턴스를 생성하고 초기화 한다.
    이때, BeanFactory와 달리 ApplicationContext는 빈의 지연 초기화(Lazy Initialzation)를 기본적으로 하지 않고,설정에 따라 빈의 인스턴스를 즉시 생성한다.

  3. 의존성 주입(Dependenecy Injection)
    빈 간의 의존성을 주입한다. 설정 메타데이터에 기술된 의존성 정보를 기반으로 빈 간의 의존성을 자동으로 해결한다.
    이를 통해 개발자는 수동으로 의존성을 설정할 필요가 없다.

  4. 빈 후처리기 적용
    빈의 초기화나 소멸 전후에 등록된 빈 후처리기를 실행한다.
    이를 통해 개발자는 빈의 생성과 초기화 과정에 개입하여 추가적인 로직을 수행할 수 있다.

  5. 싱글톤 빈관리
    싱글톤 빈으로 정의된 빈의 인스턴스를 캐싱하여 관리한다. 따라서 동일한 싱글톤 빈이 여러번 요청되면, 항상 동일한 인스턴스를 반환한다.

  6. 빈의 생명주기 관리
    빈의 초기화와 소멸에 관련된 콜백 메서드를 호출하며 빈의 생명주기를 제어한다.
    이를 통해 개발자는 빈이 생성된 후 추가적인 초기화 작업이나 빈이 소멸되기 전의 정리 작업을 수행할 수 있다.

  7. 어노테이션 기반의 빈 구성
    @Component, @Autowired, @Qualifier 등의 어노테이션을 사용하여 빈을 구성하고, 의존성을 주입할 수 있다.

그러면 ApplicationContext는 스프링 컨테이너가 시작될 때 빈을 미리 로딩한다고 하는데 그럼 BeanFactory는 언제 빈을 로딩할까?

BeanFactory


스프링 컨테이너의 최상위 인터페이스이며, getBean 메서드를 제공한다

ApplicationContext를 구현한 구현체들은
ClassPathXmlApplicationContext, FileSystemXmlApplicationContext, AnnotationConfigApplicationContext 등이 있으며
주로 AnnotationConfigApplicationContext를 사용한다

빈 생성 시기

위에서 ApplicationContext는 스프링 컨테이너가 시작될 때 미리 빈을 로딩한다고 했다.
하지만 BeanFactory는 Bean을 미리 생성하지 않고, getBean을 사용해서 호출된 시점에 빈을 생성한다.

동작 방식

  1. 빈의 정의 및 설정 로딩
    BeanFactory는 설정 메타데이터(예:XML파일)를 로딩하여 빈의 정의를 파악한다.
    이때, 각 빈의 클래스, 의존성, 초기화 방법 등의 정보를 확인힌다.

  2. 빈의 인스턴스화 및 초기화 지연
    BeanFactory는 빈의 인스턴스를 생성하는 시점을 지연시킨다.
    즉, getBean() 메서드가 호출되기 전까지는 해당 빈의 인스턴스를 생성하지 않는다.

  3. 빈 요청 시 인스턴스 생성
    getBean() 메서드가 호출되면 BeanFactory는 요청된 빈의 인스턴스를 생성한다.
    이 때 빈의 생성, 초기화, 의존성 주입 등의 작업을 수행한다.

  4. 싱글톤 빈 캐싱
    생성된 빈의 인스턴스를 캐싱하여, 이후 동일한 빈 요청이 있을 경우 캐시된 인스턴스를 반환한다.
    이는 싱글톤 빈으로 정의된 경우에만 해당되며, 다른 범위(scope)의 빈은 요청 시마다 새로운 인스턴스를 생성한다.

  5. 빈 후처리기 적용
    빈의 초기화나 소멸 전후에 등록된 빈 후처리기(BenPostProcessor)를 실행한다.
    이를 통해 개발자는 빈의 생성과 초기화 과정에 개입하여 추가적인 로직을 수행할 수 있다.

Java Bean vs Spring Bean


Bean : 애플리케이션에서 사용하는 객체(일반적으로 Bean이라고 하면, Spring Bean을 의미)
Java Bean : 단순히 클래스에서 Getter, Setter만 가지고 있는 클래스(객체)
Spring Bean : Spring 컨테이너가 관리하는 자바 객체

Spring Container 사용하기


개발자가 직접적으로 Spring Container를 사용하기 위해서는

  1. ApplicationContext의 구현체인 AnnotationConfigApplicationContext(어노테이션 기반의 자바 설정 클래스)@Configuration이 적용되어 있는 클래스 파일을 이용해서 객체를 만들어야 한다.

    스프링 컨테이너는 Configuration Metadata인 파라미터로 넘어온 설정 클래스 정보를 사용해서 스프링 빈을 등록한다.
    Configuration Metadata는 위에서 설명한 @Configuration 어노테이션과 @Bean 어노테이션, XML, 자바코드를 이용해서 설정이 가능하다.

  2. Spring Container에 등록된 빈들을 가져와 사용하려면 getBean메서드를 이용해서 사용하면 된다.
    getBean을 통해 빈을 가져오게 되면, 빈의 이름을 알아야 하므로 주도권이 개발자에게 가게되어 IoC가 깨진다

Spring Contatiner는 빈을 어떻게 생성해서 가지고 있을까?

Spring Contatiner에서 Bean을 BeanDefinition이라는 추상화로써 Spring Bean으로 가지고 있어서 가능하다.

  1. BeanDefinition 등록
    개발자가 Spring Container에 BeanDefinition을 제공하게 된다.
    이는 XML, Java Annotation, Java Code를 통해 제공될 수 있다.
    이 정보는 Bean의 클래스타입, 생성방법, 의존성 등을 담고 있다.

  2. BeanDefinition 읽기
    BeanFactory or ApplicationContext를 초기화 하는 과정에서
    Spring Container가 BeanDefinition을 읽어들인다.

  3. Bean 생성
    BeanDefinition이 읽히면, Spring Container는 해당 정보를 토대로 Bean 인스턴스를 생성한다.
    이때 생성자를 통한 생성 또는 팩토리 메서드를 통한 생성이 가능하다

  4. 의존성 주입
    생성된 Bean에 필요한 의존성이 있다면, 이를 주입하는 과정을 거친다.
    이는 생성자 주입, 세터 주입, 필드 주입 등의 방법으로 이루어진다.

  5. Bean 초기화
    Bean이 생성되고 의존성이 주입된 후, 필요한 초기화 과정을 거친다
    이때, @PostConstruct 어노테이션을 통해 지정된 메서드 또는 InitializingBean 인터페이스를 구현하여 정의된 afterPropertiesSet() 메서드가 호출된다.

  6. Bean 사용
    이제 애플리케이션에서는 Spring Container를 통해 Bean을 가져와 사용이 가능하다.
    이는 ApplicationContext.getBean() 메서드를 통해 이루어진다.

  7. Bean 소멸
    애플리케이션 종료 시점에, Spring Container는 Singleton 범위의 Bean들에 대해 소멸 과정을 거친다.
    이때 @PreDestroy 어노테이션을 통해 지정된 메서드 또는 DisposableBean 인터페이스를 구현하여 정의된 destroy() 메서드가 호출된다.

어노테이션

@Component

클래스 레벨에서 선언함으로써 스프링이 런타임시에 컴포넌트 스캔을 하여 자동으로 Bean을 찾고 등록하는 어노테이션
@ComponentSacn 어노테이션으로 인해 해당 클래스가 빈으로 등록이 된다.

@ComponentScan

이 어노테이션이 적용된 해당 클래스의 패키지와 하위 패키지에 있는 @Component 어노테이션 및 @Service, @Repository, @Controller 어노테이션들이 부여된 class를 탐색하여 빈으로 등록해주는 어노테이션

@Configuration

Bean 메타정보들을 담고 있는 클래스라고 Spring Container에게 알려주는 어노테이션

즉, 이것이 적용되어 있는 클래스는 이 안에 우리가 관리해야 할 빈들이 있다고 Spring Container에게 알려주는 어노테이션이다.

이 어노테이션이 설정된 클래스의 빈들이 싱글톤 방식으로 보장되어야 한다는 것을 알려주는 것이기도 하다.

@Bean

메서드 레벨에서 선언하며, 반환되는 객체(인스턴스)를 개발자가 수동으로 빈으로 등록하는 어노테이션이다.
해당 메소드가 반환하는 객체를 빈으로 등록해준다.

profile
안녕하세요

0개의 댓글