Spring 中的 ApplicationContext

1、概览

本文将带你详细了解 Spring 中的 ApplicationContext 接口。

2、ApplicationContext 接口

Spring 框架的主要功能之一是 IoC(控制反转)容器。Spring IoC 容器负责管理应用的对象。它使用依赖注入来实现控制反转。

BeanFactoryApplicationContext 接口,代表 Spring IoC 容器。其中,BeanFactory 是访问 Spring 容器的根接口。它提供了管理 Bean 的基本功能。

ApplicationContextBeanFactory 的子接口。因此,它具备 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

AnnotationConfigWebApplicationContextAnnotationConfigApplicationContext 的 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 实现,即 ResourceBundleMessageSourceStaticMessageSource

我们可以使用 StaticMessageSource 以编程式将消息添加到消息源中;但是,它仅支持基本的国际化,更适合用于测试而非生产环境。

ResourceBundleMessageSourceMessageSource 最常见的实现。它依赖于底层 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 接口支持事件处理。它除了支持 ContextStartedEventContextStoppedEventContextClosedEventRequestHandledEvent 等内置事件外,还支持在业务中自定义的事件。

更多关于 Spring 事件处理的详细内容,你可以参阅 这篇文章

7、总结

本文详细介绍了 Spring 中 ApplicationContext 容器,以及如何在 AppicationContext 中配置 Spring Bean。最介绍了如何创建和使用不同类型的 ApplicationContext


Ref:https://www.baeldung.com/spring-application-context