스프링 컨테이너는 스프링 프레임워크에서 가장 핵심적인 부분으로, IoC(Inversion of Control) 개념을 기반으로 만들어진 의존성 관리 및 객체 생성, 설정, 생명주기 관리를 담당하는 중추적인 역할을 합니다. 쉽게 말해 스프링 컨테이너는 객체(빈, Bean)를 생성하고 관리하는 “공장(factory)”라고 볼 수 있습니다.
스프링 컨테이너를 이용하면 결합도가 낮은(loose coupling) 애플리케이션 설계가 가능해집니다. 이는 유지보수성과 확장성에서 큰 이점을 제공합니다.
스프링 프레임워크에서 핵심적으로 제공하는 컨테이너는 크게 BeanFactory와 ApplicationContext로 나누어집니다.
실무에서는 일반적으로 ApplicationContext를 사용합니다. BeanFactory는 무척 간단한 테스트나 커스텀하게 최적화된 상황 이외엔 잘 쓰이지 않습니다.
스프링 컨테이너의 전반적인 동작 흐름은 아래와 같습니다.
스프링 컨테이너에 빈 설정 정보를 주입하는 방법은 크게 XML 설정, 자바 설정, 애노테이션 설정 으로 나눌 수 있습니다. 실무에서는 주로 애노테이션 + 자바 설정 방식을 많이 활용합니다.
과거 스프링 버전에서 가장 많이 사용되던 전통적 방식입니다. 빈의 의존관계를 명시적으로 관리하기 위해 XML 파일(applicationContext.xml 등)을 사용합니다.
<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 빈(Bean) 정의 -->
<bean id="helloService" class="com.example.service.HelloService" />
<bean id="helloController" class="com.example.controller.HelloController">
<!-- helloService 빈을 주입 -->
<property name="helloService" ref="helloService" />
</bean>
</beans>
XMLXML 파일 대신 자바 클래스를 이용하여 설정할 수 있습니다. 스프링 부트가 적극적으로 추천하는 방법이기도 하며, 애노테이션을 통한 빈 등록을 함께 사용하는 것이 일반적입니다.
@Configuration
public class AppConfig {
@Bean
public HelloService helloService() {
return new HelloService();
}
@Bean
public HelloController helloController() {
// 의존성 주입
return new HelloController(helloService());
}
}
JavaAnnotationConfigApplicationContext를 통해 위 설정 클래스를 읽어들여 스프링 컨테이너가 빈을 생성하고 주입합니다.
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
HelloController controller = context.getBean(HelloController.class);
controller.sayHello();
}
Java@Component
public class HelloService {
public String greet(String name) {
return "Hello, " + name;
}
}
@Controller
public class HelloController {
@Autowired
private HelloService helloService;
public void sayHello() {
System.out.println(helloService.greet("Spring"));
}
}
Java@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}
Java스프링 컨테이너에서의 빈 라이프사이클은 다음과 같습니다.
스프링 컨테이너는 빈마다 스코프(scope)를 지정할 수 있습니다. 스코프는 빈의 생존 범위를 뜻합니다.
실무에서 가장 많이 사용하는 스코프는 Singleton이고, 가끔 Prototype 스코프가 필요할 때도 있습니다. 웹 애플리케이션 환경이라면 Request, Session, Application 스코프도 사용할 수 있습니다.
아래 예시는 자바 기반 설정(@Configuration)과 애노테이션(@Component, @Autowired)을 활용하여 스프링 컨테이너에 빈을 등록 및 주입하는 과정을 보여줍니다.
com
└─ example
├─ AppConfig.java
├─ service
│ └─ HelloService.java
└─ controller
└─ HelloController.java
Markdown// com/example/service/HelloService.java
package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class HelloService {
public String sayHello(String name) {
return "Hello, " + name + "!";
}
}
Java// com/example/controller/HelloController.java
package com.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.example.service.HelloService;
@Controller
public class HelloController {
private final HelloService helloService;
// 생성자 주입
@Autowired
public HelloController(HelloService helloService) {
this.helloService = helloService;
}
public void processHello() {
String greeting = helloService.sayHello("Spring");
System.out.println(greeting);
}
}
Java// com/example/AppConfig.java
package com.example;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
// 필요한 경우 @Bean 정의를 추가로 넣을 수 있습니다.
}
Java// Main.java
package com.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.example.controller.HelloController;
public class Main {
public static void main(String[] args) {
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
HelloController controller = context.getBean(HelloController.class);
controller.processHello();
}
}
Java스프링 컨테이너는 스프링 프레임워크의 핵심으로, 객체 생성 및 의존성 관리를 손쉽게 해 주며, 애플리케이션 개발자가 비즈니스 로직에만 집중할 수 있도록 돕습니다. IoC와 DI 개념을 이해하고, BeanFactory와 ApplicationContext의 차이, 각 빈의 스코프(scope)와 라이프사이클 등을 이해하면 스프링을 보다 유연하고 확장성 있게 사용할 수 있습니다.
오늘날 대부분의 스프링 프로젝트는 자바 기반 설정과 애노테이션을 많이 사용하지만, XML 기반 설정도 여전히 사용될 수 있으며, 프로젝트에 따라 적절히 혼합하여 쓰기도 합니다.
스프링 컨테이너를 제대로 이해하면 결합도를 낮춘 애플리케이션 아키텍처 설계가 가능하며, 다양한 부가 기능(AOP, 트랜잭션, 국제화, 테스트 지원 등)을 자유롭게 적용할 수 있다는 점에서 스프링 생태계 전체를 잘 이해하는 발판이 됩니다.
의존성 주입(Dependency Injection)이란? 프로그램을 개발하다 보면, 여러 클래스나 객체들은 서로 필요한 기능을 사용하기 위해 관계를…
컴포넌트 스캔이란? 컴포넌트 스캔(Component Scan)은 스프링 프레임워크가 특정 패키지를 탐색하면서, 스캔 대상에 해당하는 클래스를 찾아…
스프링 빈이란? 스프링 빈(Spring Bean)은 스프링 IoC(Inversion of Control) 컨테이너가 관리하는 자바 객체를 의미합니다. 간단히…
Queue란 무엇인가? Java에서 Queue는 데이터 구조의 일종으로, 데이터를 선입선출(FIFO, First-In-First-Out) 방식으로 처리합니다. 이 글에서는 Queue의…
Stack이란 무엇인가? Java에서 Stack은 자료구조의 한 종류로, 데이터를 순서대로 쌓아 올리는 형태로 운영됩니다. 컴퓨터 과학에서…
소개 자바에서 Map 인터페이스는 키(Key)와 값(Value)의 쌍을 저장하는 자료구조입니다. 이는 연관 배열이라고도 불리며, 각 키는…