1. 概述
在本教程中,我們將詳細探討 Spring ApplicationContext 接口。
2. <em>ApplicationContext</em> 接口
Spring 框架的主要功能之一是 IoC(控制反轉)容器。Spring IoC 容器負責管理應用程序的對象。它使用依賴注入來實現控制反轉。
Spring IoC 容器和 <em>BeanFactory</em> 接口代表 Spring IoC 容器。其中,<em>BeanFactory</em> 是訪問 Spring 容器的根接口,它提供基本的管理 Bean 的功能。
另一方面,<em>ApplicationContext</em> 是 <em>BeanFactory</em> 的子接口。因此,它提供了所有 <em>BeanFactory</em> 的功能。
此外,它還提供了企業級特定功能。<em>ApplicationContext</em> 的重要功能包括解析消息、支持國際化、發佈事件以及應用程序層特定上下文。因此,我們通常將其用作默認的 Spring 容器。
3. 什麼是 Spring Bean?
在深入瞭解 ApplicationContext 容器之前,瞭解 Spring Bean 非常重要。在 Spring 中,一個 Bean 是 Spring 容器實例化、組裝和管理的對象。
所以,我們是否應該將應用程序的所有對象都配置為 Spring Bean? 實際上,作為最佳實踐,我們不應該這樣做。
根據 Spring 文檔,我們通常應該為服務層對象、數據訪問對象 (DAOs)、呈現對象以及 Hibernate SessionFactories、JMS 隊列等基礎設施對象定義 Bean。
此外,通常我們不應在容器中配置精細的領域對象。 創建和加載領域對象通常是 DAOs 和業務邏輯的責任。
現在,讓我們定義一個簡單的 Java 類,我們將用作本教程中的 Spring Bean:
public class AccountService {
@Autowired
private AccountRepository accountRepository;
// getters and setters
}4. 在容器中配置 Bean
正如我們所知,ApplicationContext 的主要職責是管理 Bean。
因此,應用程序必須向 ApplicationContext 容器提供 Bean 配置。 Spring Bean 配置包含一個或多個 Bean 定義。 此外,Spring 支持多種配置 Bean 的方式。
4.1. 基於Java的配置
首先,我們從基於Java的配置開始,因為它是在Spring 3.0版本及更高版本中最新且首選的方式。
基於Java的配置通常使用在<em @Bean</em>>-annotated 方法中,在<em @Configuration> 類中。<em @Bean</em>> 註解在一個方法中指示該方法創建Spring bean。 此外,使用<em @Configuration> 註解的類指示該類包含Spring bean配置。
現在,讓我們創建一個配置類來定義我們的`<em 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 引入了基於註解的配置作為啓用 Java 中 Bean 配置的第一步。
在這種方法中,我們首先通過 XML 配置啓用基於註解的配置。然後,我們使用一組註解來配置我們的 Java 類、方法、構造函數或字段。這些註解的例子包括 @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 {
// user service code
}然後我們編寫一個簡單的測試用例來測試這個配置:
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. 應用上下文的類型
Spring 提供了不同類型的 ApplicationContext 容器,以滿足不同的需求。這些都是 ApplicationContext 接口的實現。下面我們來看看一些常見的 ApplicationContext 類型。
5.1. <em>AnnotationConfigApplicationContext</em>
首先,讓我們看看 <em>AnnotationConfigApplicationContext</em> 類,該類自 Spring 3.0 版本開始引入。它可以接受帶有 <strong>@Configuration</strong>、`@Component, 以及 JSR-330 元數據標註的類作為輸入。
下面是一個使用 <em>AnnotationConfigApplicationContext</em> 容器的簡單示例,該示例使用了基於 Java 的配置:
ApplicationContext context = new AnnotationConfigApplicationContext(AccountConfig.class);
AccountService accountService = context.getBean(AccountService.class);5.2. <em >AnnotationConfigWebApplicationContext</em>
`AnnotationConfigWebApplicationContext> 是 AnnotationConfigApplicationContext 的一種基於Web的變體。
我們可能使用此類來配置 Spring 的 ContextLoaderListener servlet 監聽器或 Spring MVC 的 DispatcherServlet 在 web.xml 文件中。
此外,從 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. <em >XmlWebApplicationContext</em>
如果我們在 Web 應用程序中使用基於 XML 的配置,則可以使用 <em >XmlWebApplicationContext</em> 類。
事實上,配置此容器就像 <em >AnnotationConfigWebApplicationContext</em> 類一樣,這意味着我們可以通過 <em >web.xml</em > 或實現 `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. <em >FileSystemXMLApplicationContext</em >
我們使用 <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/support/FileSystemXmlApplicationContext.html"><em >FileSystemXMLApplicationContext</em ></a> 類來從文件系統或 URL 中加載基於 XML 的 Spring 配置文件。 此類在我們需要通過編程方式加載 <em >ApplicationContext</em > 時非常有用。 通常,測試套件和獨立應用程序是該類的潛在用例。
例如,讓我們看看如何創建 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. <em >ClassPathXmlApplicationContext</em ></a >
如果需要從類路徑加載 XML 配置文件,可以使用 <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/support/ClassPathXmlApplicationContext.html"><em >ClassPathXmlApplicationContext</em ></a >> 類。 類似於FileSystemXMLApplicationContext,它對測試套件以及嵌入在 JAR 文件中的應用程序上下文非常有用。
讓我們來看一個使用該類的示例:
ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext/account-bean-config.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);6. 在 Spring 中使用多個 ApplicationContext
此外,在單個應用程序中,也可能存在需要多個 ApplicationContext 實例的情況。
6.1. 模塊化應用
在大型模塊化應用中,每個模塊可能擁有自己的上下文。 這有助於隔離每個模塊的配置,防止 Bean 命名衝突,並簡化維護。
對於模塊化應用,每個模塊可以加載自己的 ApplicationContext:
// Module 1 Context
ApplicationContext module1Context = new AnnotationConfigApplicationContext(Module1Config.class);
// Module 2 Context
ApplicationContext module2Context = new AnnotationConfigApplicationContext(Module2Config.class);
每個上下文可以獨立管理其 Bean,而無需干擾其他模塊上下文。
6.2. 層次化應用上下文
Spring 允許使用層次化上下文,其中父上下文可以定義可供所有子上下文使用的 Bean,但子上下文可以擁有特定於其模塊的 Bean。 這在例如在父上下文中擁有共享的核心配置的情況下非常有用。
以下是一個父子上下文的示例:
// Parent ApplicationContext
ApplicationContext parentContext = new AnnotationConfigApplicationContext(ParentConfig.class);
// Child ApplicationContext
AnnotationConfigApplicationContext childContext = new AnnotationConfigApplicationContext();
childContext.setParent(parentContext);
childContext.register(ChildConfig.class);
childContext.refresh();
在此示例中,parentContext 首先被加載。 childContext 被創建並使用 setParent() 方法與 parentContext 鏈接。 定義在 ParentConfig 中的 Bean 將在 childContext 中可用。
6.3. 測試隔離
我們可以使用不同的 <em >ApplicationContext</em> 實例來模擬應用程序的不同部分,以便在測試過程中進行。<strong >這允許您在不影響其他部分的情況下測試應用程序的一個部分。</strong>
對於單元測試或集成測試,我們可能需要為每個測試場景創建特定的上下文:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { Module1Config.class })
public class TestClass1 {
@Autowired
ApplicationContext context1;
// Test cases
}
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { Module2Config.class })
public class TestClass2 {
@Autowired
ApplicationContext context2;
// Test cases
}這確保測試類是隔離的,並且具有自己的上下文配置。
7. ApplicationContext 的附加功能
ApplicationContext 提供了以下附加功能:
- Bean 掃描: 自動掃描項目中的所有 Bean 定義,包括 XML、註解和 Java 代碼。
- 資源訪問: 方便地訪問項目中的各種資源,如配置文件、圖像、音頻等。
- 事件發佈與訂閲: 支持事件發佈和訂閲機制,實現組件之間的鬆耦合。
- AOP 支持: 提供對面向方面編程 (AOP) 的支持,允許在不修改源代碼的情況下增強應用程序的功能。
- 事務管理: 簡化事務管理的流程,提高應用程序的可靠性。
- JNDI 支持: 支持通過 JNDI 查找和訪問 Bean。
7.1. 消息解析
<em>ApplicationContext</em> 接口支持消息解析和國際化,通過擴展MessageSource 接口來實現。 此外,Spring 提供了兩個MessageSource 實現:`ResourceBundleMessageSource 和 StaticMessageSource。
我們可以使用 <em>StaticMessageSource</em> 編程方式向源中添加消息;但是,它僅支持基本的國際化,更適合用於測試,而不是生產環境。
另一方面,<em>ResourceBundleMessageSource</em> 是 <em>MessageSource</em> 最常用的實現。 它依賴於 JDK 內置的 `ResouceBundle 實現。 它還使用 JDK 標準的消息解析,由 MessageFormat 提供。
現在讓我們看看如何使用 <em>MessageSource</em> 從 properties 文件中讀取消息。
首先,我們將 `messages.properties 文件放在類路徑上:
account.name=TestAccount第二,我們將添加一個 Bean 定義到我們的 AccountConfig 類中:
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("config/messages");
return messageSource;
}第三,我們將注入 MessageSource 到 AccountService 中:
@Autowired
private MessageSource messageSource;最後,我們可以使用 getMessage 方法在 AccountService 中的任何地方讀取消息:
messageSource.getMessage("account.name", null, Locale.ENGLISH);Spring 還提供了 ReloadableResourceBundleMessageSource 類,它允許從任何 Spring 資源位置讀取文件,並支持 bundle 屬性文件的熱重載。
7.2. 事件處理
<em>ApplicationContext</em> 通過使用 <em>ApplicationEvent</em> 類和 <em>ApplicationListener</em> 接口來支持事件處理。它內置了諸如 <em>ContextStartedEvent</em>、<em>ContextStoppedEvent</em>、<em>ContextClosedEvent</em> 和 <em>RequestHandledEvent</em> 等事件。此外,它還支持用於業務用例的自定義事件。
8. 結論
在本文中,我們探討了 Spring 中 ApplicationContext 容器的各個方面。我們還研究瞭如何配置 Spring bean 的不同示例。最後,我們學習瞭如何創建和使用不同類型的 ApplicationContext。