[Spring] Spring의 대략적인 개념
스프링 프레임워크에서는 스프링 컨텍스트에서 빈이라는 단위로 객체를 관리한다.
먼저 "스프링 컨텍스트"란?

애플리케이션 컴포넌트(빈, 설정, 환경 등)의 생명주기와 의존성을 관리하는 컨테이너
즉, Spring은 Bean 객체를 만들고, 필요한 곳에 주입하고, 필요 시 소멸까지 관리합니다.
내부적으로는 ApplicationContext 인터페이스를 통해서 BeanFactory를 상속하여 관리를 한다.
모든 Bean의 생성, 주입, 설정, 조회를 담당하는 중앙 관리소 이다.
외에 여러 구현체들이 있다.
| ClassPathXmlApplicationContext | XML 설정 기반 |
| AnnotationConfigApplicationContext | 자바 기반 설정 클래스용 |
| WebApplicationContext | 웹 앱에서 사용하는 컨텍스트 |
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = context.getBean(MyService.class);
BeanFactory 인터페이스 있지만 보통 직접 조작하는 경우가 없기에
일반적으로 ApplicationContext 를 스프링 컨테이너라고 지칭한다.

BeanFactory
- 스프링에서의 컨테이너의 최상위 인터페이스이다.
- 빈을 관리하고 조회 하는 등의 역할을 한다.
ApplicationContext
- BeanFactory를 상속받아 제공한다.
- 빈 관리를 포함하여 그밖의 여러 애플리케이션을 개발하기 위해 공통적으로 필요한 많은 부가 기능을 제공
ex :
-메시지소스를 활용한 국제화 (한국어 입력 -> 한국어 출력)
화면에서 공통으로 사용되는 다양한 메시지를 한 곳에서 관리하는 기능을 메시지 기능
messages.properties 라는 메시지 관리용 파일을 만들고, HTML안에서 Key 값으로 해당 데이터를 관리한다.
HTTP 헤더(accept-language) 값을 사용하거나 처음에 사용자가 직접 언어를 선택하게 하여 쿠키 등을 사용해서 언어를 선택
하여 감지가 가능하다.
- 환경변수: 환경 별로 로컬. 개발. 운영등을 구분해서 처리
application.properties에서 server.profiles.active = local 및 prod 관련한 기능
@ConfigurationProperties(prefix = " prod ") // prod 환경 전용 설정어노테이션
- 어플리케이션 이벤트 : 이벤트를 발행하고 구독하는 모델을 지원한다.
public class UserRegisteredEvent extends ApplicationEvent {
private final String username;
public UserRegisteredEvent(Object source, String username) {
super(source);
this.username = username;
}
public String getUsername() {
return username;
}
}
@Component
@RequiredArgsConstructor
public class UserService {
private final ApplicationEventPublisher eventPublisher;
public void registerUser(String username) {
// 회원가입 처리...
// 이벤트 발행
eventPublisher.publishEvent(new UserRegisteredEvent(this, username));
}
}
@Component
public class WelcomeEmailSender {
@EventListener
public void onUserRegistered(UserRegisteredEvent event) {
System.out.println("환영 이메일 발송: " + event.getUsername());
}
}
다양한 구현 및 설정 방식을 쥐원하는 스프링 - 어노테이션 & XML 등

다양한 구현체를 통하여 ApplicationContext를 정의할 수 있음.
1. ClassPathXmlApplicationContext
XML 설정 기반 어플리케이션 컨텍스트
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
MyService myService = ctx.getBean(MyService.class);
applicationContext.xml 같은 xml 파일을 읽어서 설정을 하는 방식이다.
과거 표준 방식이며 현대의 스프링부트에서는 거의 사용되지 않는다. 하지만 레거시 프로젝트들에서는 많이 사용되어 왔다.
(즉 유지보수 측면에서 보면 중요)
classpath 기준으로 해당파일을 읽는다.
-applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<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">
<!-- MyService 빈 등록 -->
<bean id="myService" class="com.example.MyService"/>
</beans>
2. AnnotationConfigApplicationContext
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService myService = ctx.getBean(MyService.class);
@Configuration 자바 클래스를 기반으로 설정하는 구현체이다.
현대방식에서 많이 사용되며 어노테이션 기반으로 스프링을 구성한다.
스프링의 빈 설정 메타 정보 - BeanDefinition
Spring 내부에서 Bean 객체를 생성하고 관리하기 위한 메타정보를 담은 객체
“이 Bean은 어떤 클래스이며, 어떤 방식으로 생성하고, 어떤 의존성을 주입하고, 어떤 스코프로 관리할 것인가”
를 Spring이 내부적으로 정리해놓은 정의 정보
역할과 구현 부분을 개념적으로 나눈 것이다.
- XML 읽어서 BeanDefinition 생성
- 자바 코드 읽어서 BeanDefinition 생성
스프링 컨테이너는 자바 코드 기반인지, XML 기반인지 몰라도 된다. 오직 BeanDefinition만 알면 된다. (BeanDefinition에만 의존하고 있다.)

- AnnotationConfigApplicationContext는 AnnotatedBeanDefinitionReader를 사용해 AppConfig.class(인자로 들어옴)를 읽고, BeanDefinition을 생성한다.
- GenericXmlApplicationContext는 XmlBeanDefinitionReader를 사용해 appConfig.xml 설정 정보를 읽어 BeanDefinition을 생성한다.
- 새로운 형식의 설정 정보가 추가되면, XxxBeanDefinitionReader를 만들어 BeanDefinition을 생성하도록 직접 구현할 수도 있다.
즉, Spring은 실제 객체(Bean)를 만들기 전에 **"이 Bean은 어떤 클래스이고, 어떤 방식으로 생성되고, 어떤 값들이 주입되는지"**에 대한 정보를 BeanDefinition이라는 형태로 메모리에 등록
BeanDefinition은 언제 사용되나?
- Spring의 ApplicationContext가 시작될 때:
- 모든 @Component, @Bean, XML 정의 등을 BeanDefinition으로 파싱
- 이 정의들을 BeanFactory에 등록 (DefaultListableBeanFactory 내부 map에 저장)
- Spring은 이 정의를 기반으로 실제 Bean을 지연 로딩하거나 초기화하면서 생성
내부적으로 무슨 일이 벌어질까?
- AnnotationConfigApplicationContext가 초기화됨
- 내부에서 AppConfig.class를 분석하여 @Bean/@Component 등 찾음
- 빈 정의(BeanDefinition) 생성
- 필요한 경우 의존성 주입 (생성자, @Autowired, etc)
- Bean 생성 및 초기화
- 싱글톤 스코프이면 context 내부에 캐싱
스프링은 자바에서 new 연산자로 인해 객체를 생성하는 것을 미리 SpringContext에 로드하여
싱글톤으로 관리하며 new 연산자를 대신하여 수행하고 있다.
스프링 컨텍스트(ApplicationContext)는
내부적으로 BeanDefinitionMap이라는 맵(Map 구조)에
빈 메타정보(정의)와 객체(인스턴스)**를 저장·관리하는 싱글톤 컨테이너 객체
ApplicationContext
└─ GenericApplicationContext
└─ DefaultListableBeanFactory
└─ Map<String, BeanDefinition> beanDefinitionMap ← 빈 정의들 저장
└─ Map<String, Object> singletonObjects ← 실제 객체들 저장
이러한 형태를 가진다.
========================================================================================================
WebApplicationContext
Spring MVC에서 사용하는 웹 전용 ApplicationContext
즉, 웹 관련 기능이 추가된 스프링 컨테이너 , ApplicationContext를 확장한 서블릿 전용 컨텍스트 인터페이스
Servlet Context에 접근할 수 있는 기능이 추가된 것. (DispatherSerlvet이 직접 사용하는 스프링 컨테이너)
웹 관련 빈 관리
ex : Controller, Service, Repository, View Resolver, Hanlder Mapping 등
[Root ApplicationContext] ← 비즈니스 로직 빈들 (Service, Repository 등)
↑
[WebApplicationContext] ← 웹 컨트롤러, ViewResolver, MultipartResolver 등
↑
[DispatcherServlet이 생성하고 사용하는 컨테이너]
| 항목 | ApplicationContext | WebApplicationContext |
| 용도 | 일반 자바 애플리케이션 | 웹 애플리케이션 (Servlet 기반) |
| 기능 | DI, 메시지, 리소스 로딩 등 | + 웹 객체 지원 (HttpServletRequest, Session, ServletContext) |
| 대표 클래스 | AnnotationConfigApplicationContext | AnnotationConfigWebApplicationContext |
Spring MVC의 DispatcherServlet이 실행될 때 자동으로 생성
예를 들어, Spring Boot에서 웹 서버가 뜨면 DispatcherServlet이 초기화되고,
이 때 WebApplicationContext가 만들어집니다.
구현체로는 Xml 설정 파일을 이용하는 XmlWebApplicationContext, 애너테이션 기반의 AnnotationConfigWebApplicationContext 등이 있습니다.
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/servlet-context.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
여기서 두 개의 ApplicationContext가 만들어짐
| RootContext | ContextLoaderListener가 만드는 AppContext (서비스, DAO 등 등록) |
| ServletContext (WebApplicationContext) | DispatcherServlet이 만드는 MVC 전용 컨텍스트 (Controller, View 등 등록) |
- Root-Context (Root Application) : 모든 서블릿이 공유하는 공통 영역 ( Service, Repository, DataSource, TransactionManager 등)
root-context.xml: DB, 서비스 관련 Bean
- ServletContext(WebApplicationContext) : 각 DispatcherServlet 전용 영역 (웹 MVC 관련) Controller, ViewResolver, HandlerMapping 등 , 서도 독립적이다. (다른 서블릿과 공유하지 않는다.)
servlet-context.xml: 컨트롤러, 뷰 설정 등 웹 관련 Bean
모식도

서블릿별로 하나씩 존재한다. (일반적인 스프링MVC에서는 DispatherSerlvet 하나만 존재)
하지만 의도적으로 등록하거나 대규모 시스템에서 여러 서블릿을 분리해서 관리하는 아키텍처라면 복수도 가능.
DispatcherServlet과의 관계
WebApplicationContext는 Spring MVC의 핵심 서블릿인 DispatcherServlet과 밀접한 관계를 가집니다.
- DispatcherServlet은 자신만의 WebApplicationContext를 가집니다. 클라이언트의 요청을 DispatcherServlet이 받으면, 이 DispatcherServlet은 자신에게 할당된 WebApplicationContext를 통해 요청을 처리할 적절한 컨트롤러를 찾고, 필요한 빈들을 주입하여 요청을 처리합니다.
- 계층 구조: 일반적으로 Spring 웹 애플리케이션에는 두 가지 종류의 WebApplicationContext가 존재합니다.
- Root WebApplicationContext (부모 컨텍스트): ContextLoaderListener에 의해 생성되며, 애플리케이션 전반에 걸쳐 공유되어야 하는 빈들 (예: 서비스, 데이터베이스 연결, 트랜잭션 관리)을 관리합니다.
- Servlet WebApplicationContext (자식 컨텍스트): 각 DispatcherServlet에 의해 생성되며, 해당 DispatcherServlet이 처리하는 웹 관련 빈들 (예: 컨트롤러, 뷰 리졸버)을 관리합니다. 자식 컨텍스트는 부모 컨텍스트의 빈들을 참조할 수 있습니다.