스프링 컨테이너는 스프링 프레임워크에서 가장 핵심적인 부분으로, 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, 트랜잭션, 국제화, 테스트 지원 등)을 자유롭게 적용할 수 있다는 점에서 스프링 생태계 전체를 잘 이해하는 발판이 됩니다.
Queue란 무엇인가? Java에서 Queue는 데이터 구조의 일종으로, 데이터를 선입선출(FIFO, First-In-First-Out) 방식으로 처리합니다. 이 글에서는 Queue의…
Stack이란 무엇인가? Java에서 Stack은 자료구조의 한 종류로, 데이터를 순서대로 쌓아 올리는 형태로 운영됩니다. 컴퓨터 과학에서…
소개 자바에서 Map 인터페이스는 키(Key)와 값(Value)의 쌍을 저장하는 자료구조입니다. 이는 연관 배열이라고도 불리며, 각 키는…
소개 자바에서 Set은 중복을 허용하지 않는 데이터 집합을 의미합니다. List와 달리 동일한 요소를 여러 번…
해시(Hash)란 무엇인가? 해시(Hash)는 자바 프로그래밍에서 빠르고 효율적인 데이터 저장 및 검색을 위한 핵심적인 개념입니다. 이…
입문자를 위한 Spring Boot with Kotlin - 나만의 포트폴리오 사이트 만들기 강의와 함께한 인프런 워밍업 클럽…