Spring 中的 ApplicationContext
1、概览
本文将带你详细了解 Spring 中的 ApplicationContext
接口。
2、ApplicationContext 接口
Spring 框架的主要功能之一是 IoC(控制反转)容器。Spring IoC 容器负责管理应用的对象。它使用依赖注入来实现控制反转。
BeanFactory
和 ApplicationContext
接口,代表 Spring IoC 容器。其中,BeanFactory
是访问 Spring 容器的根接口。它提供了管理 Bean 的基本功能。
而 ApplicationContext
是 BeanFactory
的子接口。因此,它具备 BeanFactory
的所有功能。
此外,它还提供了更多面向企业的特定功能。ApplicationContext
的重要功能包括解析消息、支持国际化、发布事件以及应用层特定的上下文。这就是为什么我们将其作为默认的 Spring 容器使用的原因。
3、Spring Bean 是什么?
在深入了解 ApplicationContext
容器之前,有必要了解一下 Spring Bean。在 Spring 中,Bean 是 Spring 容器实例化、组装和管理的对象。
那么,是否应该将应用的所有对象都配置为 Spring Bean 呢?作为最佳实践,不应该这样做。
一般来说,根据 Spring 文档 所述,应该为服务层对象、数据访问对象 (DAO)、表现对象、基础架构对象(如 Hibernate SessionFactory
、JMS Queue
等)定义 Bean。
此外,通常情况下,不应该在容器中配置细粒度的 Domain 对象。创建和加载 Domain 对象通常是 DAO 和业务逻辑的职责。
定义一个简单的 Java 类,在本文中用作 Spring Bean:
public class AccountService {
@Autowired
private AccountRepository accountRepository;
// Get、Set 方法省略
}
4、在容器中配置 Bean
我们知道,ApplicationContext
的主要工作是管理 Bean。
因此,应用必须向 ApplicationContext
容器提供 Bean 配置。Spring Bean 配置由一个或多个 Bean 定义(Definition)组成。此外,Spring 还支持不同的 Bean 配置方式。
4.1、基于 Java 的配置
首先,从基于 Java 的配置开始,因为它是最受欢迎的 Bean 配置方式,从 Spring 3.0 开始可用。
Java 配置通常在 @Configuration
类中使用 @Bean
注解方法。方法上的 @Bean
注解表示该方法创建了一个 Spring Bean。此外,被 @Configuration
注解标记的类表示它包含 Spring Bean 的配置信息。
创建一个配置类,将 AccountService
类定义为 Spring Bean:
@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 配置启用基于注解的配置。然后,在 Java 类、方法、构造函数或字段上使用一组注解来配置 Bean。这些注解的一些示例包括 @Component
、@Controller
、@Service
、@Repository
、@Autowired
和 @Qualifier
。
注意,我们在基于 Java 的配置中也使用了这些注解。另外,Spring 每次发布都可能会为这些注解添加更多功能。
来看一个简单的示例。
首先,创建 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>
如上,annotation-config
标签启用了基于注解的映射。component-scan
(组件扫描)标签还告诉 Spring 在哪里查找注解类。
其次,创建 UserService
类,并使用 @Component
注解将其定义为 Spring Bean:
@Component
public class UserService {
// UserService 代码
}
然后,编写一个简单的测试用例来测试此配置:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext/user-bean-config.xml");
UserService userService = context.getBean(UserService.class);
assertNotNull(userService);
4.3、基于 XML 的配置
最后,来看看基于 XML 的配置。这是 Spring 中配置 Bean 的传统方法。
显然,在这种方法中,需要在 XML 配置文件中完成所有 Bean 映射。
创建一个 XML 配置文件 account-bean-config.xml
,并把 AccountService
类定义为 Bean:
<?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
容器。这些都是 ApplicationContext
接口的实现。
下面就来看看 ApplicationContext
的一些常见类型。
5.1、AnnotationConfigApplicationContext
首先,看看在 Spring 3.0 中引入的 AnnotationConfigApplicationContext
类。它可以将使用 @Configuration
、@Component
和 JSR-330 元数据注解的类作为输入。
使用 AnnotationConfigApplicationContext
容器和基于 Java 配置的简单示例:
ApplicationContext context = new AnnotationConfigApplicationContext(AccountConfig.class);
AccountService accountService = context.getBean(AccountService.class);
5.2、AnnotationConfigWebApplicationContext
AnnotationConfigWebApplicationContext
是 AnnotationConfigApplicationContext
的 Web 版。
当在 web.xml
文件中配置 Spring 的 ContextLoaderListener
监听器或 Spring MVC DispatcherServlet
时,可能会用到该类。
从 Spring 3.0 开始,还可以以编程式配置此 Application Context 容器。只需实现 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 配置
}
}
5.3、XmlWebApplicationContext
如果在 Web 应用中使用基于 XML 的配置,可以使用 XmlWebApplicationContext
类。
事实上,配置该容器的方法与 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 配置
}
}
5.4、FileSystemXMLApplicationContext
使用 FileSystemXMLApplicationContext
类从文件系统或 URL 加载基于 XML 的 Spring 配置文件。当需要以编程方式加载 ApplicationContext
时,该类就会派上用场。通常用于测试场景或者是独立应用。
创建这个 Spring 容器并加载基于 XML 的配置中的 Bean:
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 配置文件,可以使用 ClassPathXmlApplicationContext
类。该类与 FileSystemXMLApplicationContext
类似,适用于测试环境以及嵌入在 JAR 中的 Application Context。
示例如下:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext/account-bean-config.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);
6、ApplicationContext 的其他功能
6.1、Message 解析
ApplicationContext
接口通过继承 MessageSource
接口来支持消息解析和国际化。此外,Spring 还提供了两种 MessageSource
实现,即 ResourceBundleMessageSource
和 StaticMessageSource
。
我们可以使用 StaticMessageSource
以编程式将消息添加到消息源中;但是,它仅支持基本的国际化,更适合用于测试而非生产环境。
ResourceBundleMessageSource
是 MessageSource
最常见的实现。它依赖于底层 JDK 的 ResourceBundle
实现,并使用 JDK 提供的标准消息解析(MessageFormat
)。
来看看如何使用 MessageSource
从 properties 文件中读取消息。
首先,在 classpath 上创建 messages.properties
文件:
account.name=TestAccount
其次,在 AccountConfig
类中添加一个 Bean 定义:
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("config/messages");
return messageSource;
}
接着,在 AccountService
中注入 MessageSource
:
@Autowired
private MessageSource messageSource;
最后,可以在 AccountService
的任何地方使用 getMessage
方法来读取消息:
messageSource.getMessage("account.name", null, Locale.ENGLISH);
Spring 还提供了 ReloadableResourceBundleMessageSource
类,该类允许从任何 Spring Resource 位置读取文件,并支持热重载 Bundle 属性文件。
6.2、事件处理
ApplicationContext
通过 ApplicationEvent
类和 ApplicationListener
接口支持事件处理。它除了支持 ContextStartedEvent
、ContextStoppedEvent
、ContextClosedEvent
和 RequestHandledEvent
等内置事件外,还支持在业务中自定义的事件。
更多关于 Spring 事件处理的详细内容,你可以参阅 这篇文章。
7、总结
本文详细介绍了 Spring 中 ApplicationContext 容器,以及如何在 AppicationContext 中配置 Spring Bean。最介绍了如何创建和使用不同类型的 ApplicationContext
。
Ref:https://www.baeldung.com/spring-application-context