스프링 컨테이너( IoC 컨테이너 )
스프링 컨테이너는, 어플리케이션에서 사용되는 객체들을 생성하고 관리합니다. 스프링 컨테이너는 Bean 객체의 생성및 생명주기를 관리해주고, Bean 들을 조립하여 서로를 편리하게 상호 의존(사용)하게 해줍니다.
💁 Bean이란?
스프링 IoC컨테이너에 의해 생성되고 관리되는 객체를 Bean이라고 합니다. 이 객체는 스프링 컨테이너에 의해 관리되기 때문에 자바에서처럼 new Object();로 생성되지 않습니다. 작성한 클래스를 스프링 컨테이너에 빈(Bean)으 등록 해주면, 스프링 컨테이너가 해당 클래스를 이용해 객체를 생성하고 관리해줍니다.
스프링 컨테이너는 IoC 컨테이너라고 불립니다. 컨테이너가 객체에 대한 제어권을 갖고 있다고 해서 IoC(제어의 역전)라고 합니다. 일반적으로 객체를 다른 객체에 의존하게 하기위해 해당 객체를 직접 생성하고 관리해주어야 합니다. 하지만 스프링 컨테이너를 사용하면 객체 간의 의존성 코드 내에서 명시적으로 작성하지 않고, 컨테이너가 자동으로 주입해줍니다.
이를 통해 객체 간의 결합도를 낮출 수 있고, 유연하고 확장 가능한 어플리케이션을 개발할 수 있습니다.
추가로 빈(Bean) 팩토리 또는 어플리케이션 컨텍스트라고 부르기도 합니다. 객체(Bean)의 생성과 객체(Bean) 사이의 런타임 관계를 설정하는 DI 관점으로 볼 때 컨테이너를 빈 팩토리라고 합니다.
실제 스프링 컨테이너는 단순한 DI 작업보다 더 많은 일을 합니다. DI를 위한 빈 팩토리에 엔터프라이즈 어플리케이션을 개발하는데 필요한 여러 가지 컨테이너 기능을 추가한 어플리케이션 컨텍스트라 할 수 있습니다.
스프링의 빈 팩토리와 어플리케이션 컨텍스트는 각각 기능을 대표하는 BeanFactory와 ApplicationContext라는 두 개의 인터페이스로 정의되어 있습니다. ApplicationContext 인터페이스는 BeanFactory 인터페이스를 상속한 하위 인터페이스입니다.
스프링의 IoC 컨테이너는 일반적으로 어플리케이션 컨텍스트를 말합니다. 즉, 실제로 스프링 컨테이너 또는 IoC 컨테이너는 바로 이 ApplicationContext 인터페이스를 구현한 클래스의 객체이고, 스프링 어플리케이션은 최소한 하나 이상의 IoC 컨테이너를 갖고 있습니다.
스프링 컨테이너(IoC 컨테이너)는 Spring Framework에서 객체의 생명주기를 관리하고 의존성을 주입해주는 역할을 합니다. 이를 통해 개발자는 객체 생성과 의존성 관리에 대한 부담을 덜고, 유연하고 확장성이 좋은 어플리케이션을 편리하게 구축할 수 있습니다.
스프링 컨테이너 구동
1. 스프링 프레임워크 의존성 추가
스프링 프레임워크를 사용하기 위해 프로젝트에 필요한 의존성을 추가해야 합니다. 이를 위해 Maven, Gradle 등의 빌드 도구를 사용하거나, 필요한 JAR 파일을 직접 다운로드하여 프로젝트에 추가합니다.
2. 스프링 설정 파일 작성
스프링 컨테이너를 구성하기 위한 설정 파일을 작성해야 합니다. 스프링은 XML, Java 어노테이션, 자바 기반 설정 클래스 등 다양한 방식의 설정 파일을 지원합니다. 설정 파일에는 컨테이너에 등록할 빈(Bean)들과 그들의 의존성 관계 등을 정의합니다.
3. 컨테이너 생성 (+빈 등록)
스프링 컨테이너를 생성해야 합니다. 스프링은 다양한 컨테이너 구현체를 제공하지만, 일반적으로는 `ApplicationContext 인터페이스`를 구현한 클래스를 사용합니다. 컨테이너를 설정하기 위한 일반적인 방법은 ApplicationContext 인터페이스의 구현체인 ClassPathXmlApplicationContext 또는 또 다른 구현체인 AnnotationConfigApplicationContext를 사용합니다.
// XML 기반 설정
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 어노테이션 또는 자바 기반 설정
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
컨테이너를 생성할 때 생성자의 파라미터에 구성 정보(applicationcContext.xml 또는 AppConfig.class)를 지정해주어야 합니다. 스프링 컨테이너는 전달받은 구성 정보를 사용해서 스프링 Bean을 key-value(Bean이름-Bean객체) 형식으로 등록해줍니다. Bean을 등록할 때 기본적으로 구성 정보(AppConfig.class)에 있는 메서드 이름을 사용하고, name 속성을 이용해 지정해줄 수도 있습니다. Bean 이름이 중복인 경우 원치 않은 결과가 발생할 수 있기 때문에 메서드 이름을 가급적 다르게 작성하는 것이 좋습니다.
아래 코드는 등록한 빈들을 조회하는 코드입니다. Bean은 등록만 해놓고 스프링 컨테이너가 관리해주기 때문에 아래 예제 코드는 넘겨도 무방합니다. (예제는 Annotation 방식으로 빈을 등록하였습니다.)
public class ApplicationContextTest {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);
@Test
@DisplayName("컨텍스트에 등록한 Bean 출력하기")
void findApplicationBean() {
// 스프링에 등록된 모든 Bean 이름을 조회
String[] beanDefinitionNames = ac.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
BeanDefinition beanDefinition = ac.getBeanDefinition(beanDefinitionName);
// ROLE_APPLICATION: 직접 등록한 애플리케이션 빈
// ROLE_INFRASTRUCTURE: 스프링 내부에서 사용하는 빈
if (beanDefinition.getRole() == BeanDefinition.ROLE_APPLICATION) {
// Bean 이름으로 Bean 객체(인스턴스)를 조회 ( ac.getBean() )
Object bean = ac.getBean(beanDefinitionName);
System.out.println("name = " + beanDefinitionName + ", object = " + bean);
}
}
}
}
4. 빈(Bean) 사용
컨테이너가 생성된 후에는 등록된 빈들을 사용할 수 있습니다. 컨테이너에서 빈을 가져오기 위해서는 빈의 고유한 식별자 또는 빈의 타입을 지정하여 컨테이너에 요청합니다.
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyBean myBean = context.getBean("myBean", MyBean.class);
myBean.doSomething();
- Bean 조회하는 방법
- getBean(빈 이름)
- getBean(빈 이름, 빈 Type)
- getBean(빈 Type)
- 스프링 빈이 존재하지 않으면 NoSuchBeanDefinitionException 발생
자동 주입(autowiring)을 사용하여 의존성을 자동으로 주입받을 수도 있습니다.
@Autowired
private MyDependency myDependency;
💡BeanDefinition: Bean 생성 메타데이터
BeanDefinition은 스프링 프레임워크에서 빈(Bean)을 정의하고 구성하기 위해 사용되는 메타데이터입니다. 즉, BeanDefinition은 스프링 컨테이너에 등록될 빈의 설정 정보를 나타냅니다. 이 메타데이터는 컨테이너가 빈을 생성하고 관리하는 데 필요한 정보를 제공합니다.
이 정보는 위에 설명했듯이 BeanDefinition은 XML 설정 파일, 어노테이션 또는 자바 기반 설정 클래스를 통해 정의될 수 있고 다음과 같은 정보들이 담겨져 있습니다.
- 빈의 클래스 이름
- 빈 스코프
- 생성 방법
- 초기화 및 소멸 메서드
- 프로퍼티 값 또는 참조
- 빈의 역할 등
BeanDefinition은 스프링 컨테이너에 의해 사용되며, 컨테이너는 BeanDefinition을 기반으로 빈을 생성하고 구성합니다. 또한, 컨테이너는 BeanDefinition을 사용하여 빈의 라이프사이클 관리, 의존성 주입, 프로퍼티 설정 등을 수행합니다.
BeanDefinition은 컨테이너가 관리하는 객체의 메타데이터이므로, 컨테이너를 초기화할 때 미리 정의되어야 합니다. 컨테이너는 BeanDefinition을 읽고 해석하여 빈을 생성하고 관리합니다.
💡WebApplicationContext: Web에서 쓰이는 ApplicationContext 구현체
WebApplicationContext는 스프링 프레임워크에서 웹 애플리케이션 개발을 위해 제공되는 ApplicationContext의 구현체입니다. 이름 그대로 웹 환경에서 사용할 때 필요한 기능이 추가된 어플리케이션 컨텍스트입니다.
스프링 어플리케이션은 대부분 서블릿 기반의 독립 웹 어플리케이션(WAR)으로 만들어지고, WebApplicationContext는 서블릿 컨텍스트(ServletContext)와 밀접하게 연관되어 웹 애플리케이션에서 스프링을 사용하는 데 필요한 기능과 특성을 제공합니다.
- XML 설정 파일을 사용: XmlWebApplicationContext
- 어노테이션을 사용: AnnotationConfigWebApplicationContext
스프링 IoC 컨테이너는 빈 설정 메타정보를 이용해 빈 오브젝트를 만들고 DI 작업을 수행합니다. 하지만 그것만으로는 어플리케이션이 동작하지 않습니다. Java 어플리케이션을 사용할 때 main() 메소드처럼 특정 빈 오브젝트의 메소드를 호출함으로 어플리케이션을 동작시켜야 합니다.
웹 환경에서는 이런 main() 메소드 역할을 서블릿(Servlet)이 합니다. 서블릿 컨테이너가 브라우저로부터 오는 HTTP 요청을 받아서 해당 요청에 매핑되어 있는 서블릿을 실행해주는 방식으로 동작합니다. 즉 웹 어플리케이션에서 스프링 어플리케이션을 기동시키는 방법은 main() 메소드 역할인 서블릿(Servlet)을 만들어두고, 미리 어플리케이션 컨텍스트를 생성해둔 다음, 요청이 서블릿으로 들어올 때마다 getBean()으로 필요한 빈을 가져와 정해진 메소드를 그냥 실행시켜 기동시키는 구조입니다.
스프링은 이런 웹 환경에서 어플리케이션 컨텍스트를 생성하고 설정 메타 정보로 초기화해주고, 클라이언트로부터 들어오는 요청마다 적절한 빈을 찾아서 이를 실행해주는 기능을 가진 DispatcherServlet이라는 이름의 서블릿을 제공합니다.
스프링이 제공해준 서블릿을 web.xml에 등록하는 것만으로 웹 환경에서 스프링 컨테이너가 만들어지고 어플리케이션을 실행할 수 있습니다.
'Spring Framework' 카테고리의 다른 글
Spring 빈(Bean) 등록 방법 ( XML, Annotation, Java 설정 클래스 ) (0) | 2022.08.20 |
---|---|
Spring IoC 컨테이너 계층구조 및 구성(웹 어플리케이션) (0) | 2022.08.20 |
Spring 스프링의 핵심 이해: IoC/DI, AOP, PSA (0) | 2022.08.17 |
Spring 스프링이란? ( + POJO ) (0) | 2022.08.17 |
Spring 스프링(Spring) 설치하기 (feat. Eclipse) (0) | 2022.07.27 |