1. 概述
本文深入剖析 Spring 框架中的核心组件 —— ApplicationContext
。作为 Spring IoC 容器的代表,它是整个应用上下文的中枢。理解它,是掌握 Spring 的关键一步。
2. ApplicationContext 接口
Spring 框架的核心特性之一就是 IoC(控制反转)容器。这个容器负责管理应用中所有对象的生命周期和依赖关系,通过依赖注入(DI)实现控制反转。
BeanFactory
和 ApplicationContext
这两个接口代表了 Spring 的 IoC 容器:
- ✅
BeanFactory
:是访问 Spring 容器的根接口,提供了管理 Bean 的基础功能。 - ✅
ApplicationContext
:是BeanFactory
的子接口,因此它天然继承了BeanFactory
的所有能力。
更重要的是,ApplicationContext
提供了更丰富的、面向企业级应用的功能,这才是我们日常开发中首选它的原因:
- ✅ 国际化(i18n)支持:通过
MessageSource
实现消息解析。 - ✅ 事件发布与监听:基于
ApplicationEvent
和ApplicationListener
。 - ✅ 资源访问:方便地加载文件、URL 等资源。
- ✅ 应用层上下文:如 Web 应用中的
WebApplicationContext
。
简单来说,BeanFactory
是“能用”,而 ApplicationContext
是“好用且功能完备”。
3. 什么是 Spring Bean?
在深入 ApplicationContext
之前,必须明确 Spring Bean 的概念。
Spring Bean 是指由 Spring 容器实例化、装配和管理的任何对象。
⚠️ 一个常见的误区:是否要把应用中的所有对象都配置成 Bean?
答案是否定的。根据 Spring 官方的最佳实践:
- ✅ 应该配置为 Bean 的对象:
- 服务层对象(Service)
- 数据访问对象(DAO/Repository)
- 表现层对象(Controller)
- 基础设施对象(如 Hibernate
SessionFactory
, JMSQueue
等)
- ❌ 不应配置为 Bean 的对象:
- 细粒度的领域模型对象(Domain Objects)。这些对象通常由 DAO 或业务逻辑在运行时创建和加载。
下面是一个典型的 Service 类,我们将把它作为 Spring Bean 使用:
public class AccountService {
@Autowired
private AccountRepository accountRepository;
// getters and setters
}
4. 在容器中配置 Bean
ApplicationContext
的核心职责就是管理 Bean,因此我们需要向容器提供 Bean 的配置信息。Spring 支持多种配置方式,各有适用场景。
4.1. 基于 Java 的配置(推荐)
这是 Spring 3.0 之后最推荐的配置方式,类型安全、易于重构。
核心注解:
@Configuration
:标记一个类为配置类。@Bean
:标记一个方法,其返回值将被注册为一个 Bean。
示例:创建一个配置类来定义 AccountService
和 AccountRepository
:
@Configuration
public class AccountConfig {
@Bean
public AccountService accountService() {
return new AccountService(accountRepository());
}
@Bean
public AccountRepository accountRepository() {
return new AccountRepository();
}
}
4.2. 基于注解的配置
从 Spring 2.5 开始引入,是迈向“零 XML”的第一步。
关键点:
- 需要在 XML 中启用注解扫描。
- 使用
@Component
,@Service
,@Repository
,@Controller
等注解标记类。 - 使用
@Autowired
,@Qualifier
等注解进行依赖注入。
示例:
- 创建 XML 配置文件
user-bean-config.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.baeldung.applicationcontext"/>
</beans>
⚠️
<context:annotation-config/>
启用注解驱动的依赖注入。<context:component-scan>
指定 Spring 扫描带注解类的包路径。
- 创建
UserService
类并用@Component
标记:
@Component
public class UserService {
// user service code
}
- 测试加载:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext/user-bean-config.xml");
UserService userService = context.getBean(UserService.class);
assertNotNull(userService);
4.3. 基于 XML 的配置
这是 Spring 最传统的配置方式,虽然现在用得少了,但在维护老项目时仍会遇到。
所有 Bean 的定义和依赖关系都写在 XML 文件中。
示例:创建 account-bean-config.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">
<bean id="accountService" class="com.baeldung.applicationcontext.AccountService">
<constructor-arg name="accountRepository" ref="accountRepository" />
</bean>
<bean id="accountRepository" class="com.baeldung.applicationcontext.AccountRepository" />
</beans>
5. ApplicationContext 的类型
Spring 提供了多种 ApplicationContext
实现,以适应不同环境。
5.1. AnnotationConfigApplicationContext
适用于纯 Java 配置的非 Web 应用(如独立应用、单元测试)。
它可以接收 @Configuration
、@Component
等注解类作为输入。
ApplicationContext context = new AnnotationConfigApplicationContext(AccountConfig.class);
AccountService accountService = context.getBean(AccountService.class);
5.2. AnnotationConfigWebApplicationContext
这是 AnnotationConfigApplicationContext
的 Web 版本。
当你在 web.xml
中配置 ContextLoaderListener
或 Spring MVC 的 DispatcherServlet
时,可以使用它。
从 Spring 3.0 开始,也可以通过实现 WebApplicationInitializer
接口进行编程式配置:
public class MyWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(AccountConfig.class);
context.setServletContext(container);
// servlet configuration
}
}
5.3. XmlWebApplicationContext
如果你的 Web 应用使用 XML 配置,则使用此类。
配置方式与 AnnotationConfigWebApplicationContext
类似,同样支持 web.xml
或 WebApplicationInitializer
。
public class MyXmlWebApplicationInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
XmlWebApplicationContext context = new XmlWebApplicationContext();
context.setConfigLocation("/WEB-INF/spring/applicationContext.xml");
context.setServletContext(container);
// Servlet configuration
}
}
5.4. FileSystemXmlApplicationContext
用于从文件系统路径或 URL 加载 XML 配置文件。
常见于需要手动指定配置文件路径的独立应用或测试脚本。
String path = "C:/myProject/src/main/resources/applicationcontext/account-bean-config.xml";
ApplicationContext context = new FileSystemXmlApplicationContext(path);
AccountService accountService = context.getBean("accountService", AccountService.class);
5.5. ClassPathXmlApplicationContext
用于从类路径(classpath) 加载 XML 配置文件。
这是测试中最常用的加载方式,也适用于嵌入在 JAR 包中的应用上下文。
ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext/account-bean-config.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);
6. ApplicationContext 的附加功能
除了管理 Bean,ApplicationContext
还提供了强大的附加功能。
6.1. 消息解析(国际化)
ApplicationContext
通过继承 MessageSource
接口来支持消息解析和国际化。
主要实现类:
- ✅
ResourceBundleMessageSource
:最常用,基于 JDK 的ResourceBundle
。 - ✅
StaticMessageSource
:适合测试,可编程添加消息。 - ✅
ReloadableResourceBundleMessageSource
:支持从任意资源位置加载,并可热重载属性文件。
使用步骤:
- 在类路径下创建
messages.properties
文件:
account.name=TestAccount
- 在配置类中定义
MessageSource
Bean:
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("config/messages"); // 注意路径
return messageSource;
}
- 在
AccountService
中注入MessageSource
:
@Autowired
private MessageSource messageSource;
- 获取消息:
messageSource.getMessage("account.name", null, Locale.ENGLISH);
6.2. 事件处理
ApplicationContext
提供了内置的事件发布/订阅机制。
- ✅ 核心组件:
ApplicationEvent
(事件)和ApplicationListener
(监听器)。 - ✅ 内置事件:如
ContextStartedEvent
,ContextStoppedEvent
,ContextClosedEvent
。 - ✅ 自定义事件:可以轻松创建自己的业务事件。
这为解耦组件、实现观察者模式提供了非常方便的手段。
7. 总结
本文系统性地介绍了 Spring ApplicationContext
:
- 它是
BeanFactory
的增强版,提供了企业级功能。 - 掌握了三种 Bean 配置方式:Java、注解、XML。
- 了解了五种主要的
ApplicationContext
实现及其适用场景。 - 学习了其核心附加功能:国际化和事件处理。
ApplicationContext
是 Spring 应用的“心脏”,理解透彻后,再看 Spring Boot 的自动配置,就会豁然开朗。真正的“踩坑”少,开发效率高。
本文完整代码示例可参考 GitHub 仓库:https://github.com/baeldung/tutorials