반응형
Spring에서 사용되는 핵심 기능인 Spring Container에 대해서 알아보자
1. 스프링 컨테이너란?
스프링 컨테이너는 스프링 프레임워크의 핵심 부분이다. 이 컨테이너는 BeanFactory를 상속받는 ApplicationContext 인터페이스를 구현한다. Bean은 스프링 컨테이너에 의해 인스턴스화, 구성, 관리되는 객체(Class)이다.
- BeanFactory:
- 가장 기본적인 형태의 스프링 컨테이너로서, 빈의 생성, 설정, 관리 등의 역할을 담당한다. BeanFactory는 빈의 생명주기를 관리하고, 의존성 주입(DI)를 지원하며, 빈 간의 관계를 설정하는 기능을 제공한다.
- 가장 기본적인 형태의 스프링 컨테이너로서, 빈의 생성, 설정, 관리 등의 역할을 담당한다. BeanFactory는 빈의 생명주기를 관리하고, 의존성 주입(DI)를 지원하며, 빈 간의 관계를 설정하는 기능을 제공한다.
- ApplicationContext:
- BeanFactory의 확장된 형태로, BeanFactory의 모든 기능을 포함(빈의 생성, 설정 관리)하고 추가적으로 메시지 소스 처리(국제화 지원), 이벤트 발행, 애플리케이션 계층 통합 지원 등 엔터프라이즈 전반에 걸친 기능을 제공한다.
2. 스프링 컨테이너의 주요 기능
- 빈 관리:
- 스프링 컨테이너는 빈의 생성, 의존성 주입, 라이프사이클 관리 등을 담당한다. 컨테이너는 애플리케이션의 설정 정보를 바탕으로 빈을 생성하고, 의존성을 주입하며, 빈을 제공하고, 더 이상 필요하지 않은 빈을 소멸시킨다.
- 스프링 컨테이너는 빈의 생성, 의존성 주입, 라이프사이클 관리 등을 담당한다. 컨테이너는 애플리케이션의 설정 정보를 바탕으로 빈을 생성하고, 의존성을 주입하며, 빈을 제공하고, 더 이상 필요하지 않은 빈을 소멸시킨다.
- 의존성 주입(DI):
- 스프링 컨테이너는 빈 간의 의존성을 관리한다. 컨테이너는 빈의 생성 시점에 의존성을 주입하여 빈 간의 결합도를 낮추고, 코드의 재사용성과 테스트 용이성을 높여준다.
- 스프링 컨테이너는 빈 간의 의존성을 관리한다. 컨테이너는 빈의 생성 시점에 의존성을 주입하여 빈 간의 결합도를 낮추고, 코드의 재사용성과 테스트 용이성을 높여준다.
- 설정 정보 관리:
- 스프링 컨테이너는 XML, 어노테이션, Java 코드 등 다양한 형태의 설정 정보를 읽고 해석한다. 이 설정 정보는 빈의 정의, 의존성 관계, 빈의 스코프 등 애플리케이션의 구성 정보를 담고 있다.
3. ApplicationContext의 종류
- AnnotationConfigApplicationContext:
- 이 Context를 주로 사용한다. 어노테이션 기반의 설정 정보를 읽는 데 사용되는 ApplicationContext이다. @Configuration과 같은 어노테이션을 사용한 Java 설정 클래스를 읽어들인다.
- 이 Context를 주로 사용한다. 어노테이션 기반의 설정 정보를 읽는 데 사용되는 ApplicationContext이다. @Configuration과 같은 어노테이션을 사용한 Java 설정 클래스를 읽어들인다.
- ClassPathXmlApplicationContext:
- XML 기반의 설정 정보를 읽는 데 사용되는 ApplicationContext이다. 클래스패스에서 지정된 위치의 XML 설정 파일을 읽어들인다.
- XML 기반의 설정 정보를 읽는 데 사용되는 ApplicationContext이다. 클래스패스에서 지정된 위치의 XML 설정 파일을 읽어들인다.
- FileSystemXmlApplicationContext:
- 파일 시스템 경로에서 XML 설정 파일을 읽는 데 사용되는 ApplicationContext이다.
- 파일 시스템 경로에서 XML 설정 파일을 읽는 데 사용되는 ApplicationContext이다.
- WebApplicationContext:
- 웹 어플리케이션에서 사용되는 ApplicationContext이다. 서블릿 컨테이너와 통합하여 웹 어플리케이션에 대한 설정을 담당한다.
- 웹 어플리케이션에서 사용되는 ApplicationContext이다. 서블릿 컨테이너와 통합하여 웹 어플리케이션에 대한 설정을 담당한다.
4. ApplicationContext을 사용하는 이점
- 빈 관리:
- ApplicationContext는 빈 팩토리의 역할을 하며, 빈의 생성과 관리, 라이프사이클, 설정 등을 담당해준다.
- ApplicationContext는 빈 팩토리의 역할을 하며, 빈의 생성과 관리, 라이프사이클, 설정 등을 담당해준다.
- 메시지 소스 처리:
- 국제화(i18n) 지원을 위해 메시지 소스 처리 기능을 제공한다.
- 국제화(i18n) 지원을 위해 메시지 소스 처리 기능을 제공한다.
- 이벤트 퍼블리케이션:
- 애플리케이션 이벤트를 발행하고 처리하는 메소드를 제공한다.
- 애플리케이션 이벤트를 발행하고 처리하는 메소드를 제공한다.
- 다양한 뷰 레이어 기술 지원:
- JSP, Thymeleaf, FreeMarker 등 다양한 뷰 레이어 기술에 대한 통합 지원을 제공한다.
5. 스프링 컨테이너의 주요 기능
5-1. 빈 생성
- 스프링 컨테이너는 구성 파일에서 빈 정의를 읽어서 객체를 생성한다. 이 구성 파일은 XML, Java, Groovy 등 다양한 형식이 될 수 있다.
- Spring Boot에서는 XML 기반의 구성을 대신하여 주로 Java 기반의 구성을 사용하며, 이 과정에서 @Component 어노테이션을 사용하여 빈을 등록한다.
@Component를 사용한 스프링 부트의 빈 등록 예시
- @Component 어노테이션을 클래스 상단에 적어줘서 이 클래스를 스프링 빈으로 등록시킨다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
private final MyService myService;
@Autowired
public MyComponent(MyService myService) {
this.myService = myService;
myService.doSomething(); // Output: Doing something!
}
}
@Configuration과 @Bean을 사용해서 빈을 등록하는 예시
- @Configuration 어노테이션은 해당 클래스가 스프링의 설정 클래스임을 나타낸다. @Bean 어노테이션은 해당 메서드가 빈을 생성하고 초기화하는 역할을 하며, 스프링 컨테이너에 의해 관리된다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfiguration {
@Bean
public MyService myService() {
return new MyService();
}
}
class MyService {
public void doSomething() {
System.out.println("Doing something!");
}
}
5-2. 빈 주입 (Dependency Injection)
- 스프링 컨테이너는 빈이 필요로 하는 의존성을 주입한다. 이 의존성 주입은 생성자 주입이나 세터 주입을 통해 이루어진다.
- Spring Framework의 핵심 기능 중 하나는 Inversion of Control(IoC)“제어의 역전”과 Dependency Injection(DI)“의존성 주입” 이다.
- IoC (Inversion of Control)
- IoC는 객체가 자신이 사용할 객체를 직접 만들지 않고(new 사용 X) 외부에서 주입받는 개념이다(스프링 컨테이너를 통해). 이를 통해 코드 간의 결합도를 낮추고 유연성을 높일 수 있다.
- IoC는 객체가 자신이 사용할 객체를 직접 만들지 않고(new 사용 X) 외부에서 주입받는 개념이다(스프링 컨테이너를 통해). 이를 통해 코드 간의 결합도를 낮추고 유연성을 높일 수 있다.
- DI (Dependency Injection)
- DI는 IoC의 한 형태로, 객체가 필요로 하는 의존성을 외부에서 주입하는 기법이다. 생성자 주입과 세터 주입이 대표적인 방법이다.
- IoC (Inversion of Control)
예시 코드 - 서비스 인터페이스와 구현체 정의
public interface MyService {
void doSomething();
}
@Component
public class MyServiceImpl implements MyService {
@Override
public void doSomething() {
System.out.println("Doing something!");
}
}
- 생성자 주입 예시
@Component
public class MyComponentWithConstructorInjection {
private final MyService myService;
@Autowired
public MyComponentWithConstructorInjection(MyService myService) {
this.myService = myService;
}
public void execute() {
myService.doSomething(); // Output: Doing something!
}
}
- Setter 주입 예시
@Component
public class MyComponentWithSetterInjection {
private MyService myService;
@Autowired
public void setMyService(MyService myService) {
this.myService = myService;
}
public void execute() {
myService.doSomething(); // Output: Doing something!
}
}
- 위의 예시에서 MyComponentWithConstructorInjection 클래스는 생성자 주입을 사용하고, MyComponentWithSetterInjectrion 클래스는 setter 주입을 사용한다.
- 스프링 컨테이너는 @Autowired 어노테이션을 통해 해당 객체가 필요로 하는 의존성을 자동으로 주입한다. 이렇게 하면 개발자는 의존성을 직접 관리할 필요없이 필요한 의존성에 대해서 명시만 하면 된다,
- 이를 통해 각 클래스는 필요한 의존성만 명시하면, 스프링 컨테이너가 해당 객체를 생성하고, 연결하는 작업을 담당한다.
5-3. 스프링 빈이 주입되는 순서와 과정
- 빈 정의 읽기:
- 스프링 컨테이너는 @Component, @Service, @Repository, @Controller 등의 어노테이션이 붙은 클래스와 @Bean 어노테이션이 붙은 메서드를 찾아 빈 정의를 읽는다.
- 스프링 컨테이너는 @Component, @Service, @Repository, @Controller 등의 어노테이션이 붙은 클래스와 @Bean 어노테이션이 붙은 메서드를 찾아 빈 정의를 읽는다.
- 빈 생성:
- 스프링 컨테이너는 빈 정의를 기반으로 빈 인스턴스를 생성한다. 이때 생성자와 필드, 세터 메서드에 붙은 @Autowired 어노테이션을 찾아 의존성을 주입할 대상을 파악한다.
- 스프링 컨테이너는 빈 정의를 기반으로 빈 인스턴스를 생성한다. 이때 생성자와 필드, 세터 메서드에 붙은 @Autowired 어노테이션을 찾아 의존성을 주입할 대상을 파악한다.
- 의존성 해석:
- 스프링 컨테이너는 각 빈이 의존하는 다른 빈을 찾아 의존성 그래프를 만든다. 순환 의존성이 있는 경우 예외가 발생한다.
- 스프링 컨테이너는 각 빈이 의존하는 다른 빈을 찾아 의존성 그래프를 만든다. 순환 의존성이 있는 경우 예외가 발생한다.
- 의존성 주입:
- 의존성 그래프를 기반으로 의존성을 주입한다. 주입 순서는 의존성 그래프의 특성에 따라 달라질 수 있으며, 일반적으로 루트 빈부터 리프 빈까지 주입된다.
- 생성자 주입: 생성자가 호출되는 시점에 의존성이 주입된다.
- 세터 주입: 빈이 생성된 후 세터 메서드가 호출되는 시점에 의존성이 주입된다.
- 필드 주입: 빈이 생성된 후 필드에 직접 의존성이 주입된다.
- 의존성 그래프를 기반으로 의존성을 주입한다. 주입 순서는 의존성 그래프의 특성에 따라 달라질 수 있으며, 일반적으로 루트 빈부터 리프 빈까지 주입된다.
- 빈 초기화:
- @PostConstruct 어노테이션이 붙은 메서드가 있다면 호출되어 빈이 초기화된다.
- @PostConstruct 어노테이션이 붙은 메서드가 있다면 호출되어 빈이 초기화된다.
- 빈 사용:
- 이제 응용 프로그램은 완전히 초기화된 빈을 사용할 수 있다.
- 이제 응용 프로그램은 완전히 초기화된 빈을 사용할 수 있다.
- 빈 소멸:
- 응용 프로그램이 종료되거나 컨텍스트가 닫히는 경우, @PreDestroy 어노테이션이 붙은 메서드가 호출되고 빈이 소멸된다.
- 응용 프로그램이 종료되거나 컨텍스트가 닫히는 경우, @PreDestroy 어노테이션이 붙은 메서드가 호출되고 빈이 소멸된다.
- 이렇게 스프링은 개발자 대신에 의존성 주입을 처리하며, 이는 코드의 재사용성, 테스트 용이성 등 여러 가지 장점을 가져다 준다. 참고로 Spring 4.3부터는 한 개의 생성자만 있는 경우 @Autowired를 생략해도 스프링이 자동으로 의존성을 주입해준다. 따라서 위의 예제에서는 생성자(Constructor)에 @Autowired를 생략해도 무방하다.
빈 관리 - 위와 동일한 내용
- 스프링 컨테이너는 빈의 생명주기를 관리한다. 컨테이너는 빈을 생성하고, 의존성을 주입하며, 사용자에게 제공하고, 필요하면 소멸시킨다.
- 인스턴스화 (Instantiation):
- 스프링 컨테이너는 Bean 설정 정보(@Configuration)를 바탕으로 Bean 객체를 생성한다. 이는 객체 지향 프로그래밍에서 클래스를 사용해 객체를 생성하는 것과 비슷하다.
- 스프링 컨테이너는 Bean 설정 정보(@Configuration)를 바탕으로 Bean 객체를 생성한다. 이는 객체 지향 프로그래밍에서 클래스를 사용해 객체를 생성하는 것과 비슷하다.
- 의존성 주입 (Dependency Injection):
- 빈이 다른 빈을 필요로 하는 경우, 스프링 컨테이너는 의존성 주입(Dependency Injectrion: DI)을 수행한다. 이는 ⭐️생성자 주입⭐️, 세터 메서드 주입 등 여러 방식을 통해 이루어질 수 있다. → 생성자 주입을 추천한다.
- 빈이 다른 빈을 필요로 하는 경우, 스프링 컨테이너는 의존성 주입(Dependency Injectrion: DI)을 수행한다. 이는 ⭐️생성자 주입⭐️, 세터 메서드 주입 등 여러 방식을 통해 이루어질 수 있다. → 생성자 주입을 추천한다.
- 초기화 (Initialization):
- 빈의 모든 의존성이 주입되면 초기화 메서드가 실행된다. @PostConstruct 어노테이션이 붙은 메서드나, InitializingBean 인터페이스의 afterPropertiesSet 메서드 등이 여기에 해당한다.
- 빈의 모든 의존성이 주입되면 초기화 메서드가 실행된다. @PostConstruct 어노테이션이 붙은 메서드나, InitializingBean 인터페이스의 afterPropertiesSet 메서드 등이 여기에 해당한다.
- 사용 (Usage):
- 이제 빈은 준비가 완료되었으므로 애플리케이션에서 사용된다. 이 단계에서 빈은 요청에 따라서 여러 작업을 수행한다.
- 이제 빈은 준비가 완료되었으므로 애플리케이션에서 사용된다. 이 단계에서 빈은 요청에 따라서 여러 작업을 수행한다.
- 소멸 (Destruction):
- 애플리케이션 종료 시, 빈의 생명주기는 끝나게 된다. 이 때 @PreDestroy 어노테이션이 붙은 메서드나, DisposableBean 인터페이스의 destroy 메서드 등이 실행된다.
- 애플리케이션 종료 시, 빈의 생명주기는 끝나게 된다. 이 때 @PreDestroy 어노테이션이 붙은 메서드나, DisposableBean 인터페이스의 destroy 메서드 등이 실행된다.
- 스프링 컨테이너의 핵심 역할 중 하나는 이러한 빈의 생명주기를 관리하는 것이다. 이를 통해 개발자는 복잡한 객체 생성, 설정, 소멸 과정을 직접 처리할 필요 없이 비즈니스 로직에 집중할 수 있다.
5-4. 빈 설정
- 스프링 컨테이너는 빈의 특성을 설정한다. 예를 들어, 빈의 범위(scope)는 singleton, prototype 등으로 설정할 수 있다.
- 스프링에서 빈의 설정은 그 특성과 동작을 결정하는 데 사용되는 중요한 부분이다. 빈 설정에는 빈의 클래스명, 범위(scope), 의존성, 초기화 및 소멸 메서드 등이 포함될 수 있다.
- 스프링에서 빈의 범위는 그 빈이 어떻게 생성되고 공유되는지를 결정한다. 가장 많이 사용되는 빈의 범위는 다음과 같다.
- Singleton (싱글톤):
- 이 범위가 기본값이다. 스프링 컨테이너는 Bean을 한 번만 생성하고, 모든 요청에 대해 동일한 인스턴스를 재사용한다. 즉, 스프링 컨테이너당 Bean 인스턴스(생성된 클래스를 의미) 하나를 갖는다. 이 범위는 상태를 가지지 않는 빈에 적합하다.
@Component
@Scope("singleton") // 생략 가능. 기본값이 singleton이기 때문입니다.
public class SingletonBean {
// ...
}
- Prototype (프로토타입):
- 이 범위를 설정하면, 스프링 컨테이너는 빈 요청이 있을 때마다 새로운 인스턴스를 생성한다. 즉, 요청할 때마다 새로운 빈 인스턴스를 반환한다. 이 범위는 각 요청이 독립적인 상태를 필요로 하는 빈에 적합하다.
@Component
@Scope("prototype")
public class PrototypeBean {
// ...
}
- 이 외에도 웹 애플리케이션 컨텍스트에서 사용되는 request, session, application 등의 빈 범위도 있다.
- 이들은 각각 HTTP 요청, HTTP 세션, ServletContext 수명주기에 빈의 생명주기를 연결한다.
- 빈의 범위를 올바르게 설정하는 것은 애플리케이션의 성능, 동시성 관리, 메모리 관리 등에 큰 영향을 미칠 수 있다. 따라서 빈의 사용 패턴과 상태에 따라 적절한 범위를 선택해야 한다. → 주로 Singleton을 그냥 사용한다.(안건드린다)
6. 스프링 컨테이너 - AnnotationConfigApplicationContext
- 일반적으로, 스프링 기반 애플리케이션에서 어노테이션(@Component, @Controller, @Repository, @Service 등)를 사용하여 빈을 정의하면, 그 설정 정보를 해석하고 애플리케이션 컨텍스트를 구성하기 위해 AnnotationConfigApplicationContext가 사용된다.
AnnotationConfigApplicationContext는 ApplicationContext 인터페이스를 구현한 클래스 중 하나이다.
- 이 클래스는 Java의 어노테이션을 기반으로 스프링 빈 설정 정보를 읽어 들인다.
- 이 클래스를 사용하면 XML 기반의 설정 정보 대신 Java 클래스를 사용하여 스프링의 설정 정보를 정의할 수 있다.
- 이런 설정 클래스는 일반적으로 클래스명을 xxxConfig로 만들고 클래스 상단에 @Configuration 어노테이션으로 표시해준다.
다음은 AnnotationConfigApplicationContext를 사용하는 예제코드이다.
@Configuration
public class AppConfig {
@Bean
public MyClass myClass() {
return new MyClass();
}
}
- 그리고 AnnotationConfigApplicationContext는 이 AppConfig 클래스를 사용하여 스프링 컨테이너를 초기화한다. 이 컨테이너는 AppConfig 클래스에 정의된 빈 설정 정보를 바탕으로 빈 객체를 생성하고 관리한다.
- 따라서 AnnotationConfigApplicationContext는 스프링 컨테이너를 설정하고 초기화하는 역할을 하는 클래스이다. 이 클래스를 통해 어노테이션 기반의 설정 정보를 사용하여 스프링 컨테이너를 만들 수 있다.
- 스프링 부트와 같은 상위 수준의 프레임워크에서는 이런 세부 사항(빈 등록 및 초기화 작업)을 대신 처리해주는 경우가 많다.
- 스프링 부트 어플리케이션을 실행하면, SpringApplication.run(....) 메서드가 알아서 어플리케이션 컨텍스트를 생성하고 초기화한다. 이 과정에서 어노테이션 기반의 설정 정보가 사용되므로 내부적으로는AnnotationConfigApplicationContext와 같은 클래스가 사용되지만, 개발자가 직접 이 클래스를 사용하는 것은 아니다. (즉, 스프링부트가 알아서 이 클래스를 사용해 빈을 등록하고 초기화하고 삭제한다.)
2023.07.20 - [Spring 기초/기초 지식] - [스프링, 스프링부트] Spring Framework
반응형
'Spring 기초 > Spring 기초 지식' 카테고리의 다른 글
스프링의 핵심: Singleton 패턴 알아보기 (0) | 2023.08.07 |
---|---|
스프링 프레임워크의 핵심: 제어의 역전(IoC) (0) | 2023.08.07 |
[스프링, 스프링부트] Spring - 의존성 주입(DI - Dependency Injection) (0) | 2023.08.07 |
[스프링, 스프링부트] Spring - @Bean과 @Component (0) | 2023.07.20 |
[스프링, 스프링부트] Spring Framework (0) | 2023.07.20 |