Spring之ApplicationContext

時空穿越者發表於2021-09-05

ApplicationContext

ApplicationContext是Spring的高階容器。

與BeanFactory類似,它可以載入bean定義並根據請求分發bean;此外,它還新增了很多特定的功能,比如:從屬性檔案解析文字訊息、將應用程式事件釋出到感興趣的事件偵聽器。

類圖

可以使用如下程式碼建立ApplicationContext:

ApplicationContext context = new FileSystemXmlApplicationContext("Beans.xml");

Spring提供了適合不同需求的ApplicationContext,每個應用程式上下文可以擁有多個配置檔案、配置類或兩者的混合,相關類圖見下圖:

解讀:

  • ConfigurableApplicationContext

ConfigurableApplicationContext 擴充套件自 ApplicationContext,新增了兩個主要方法 reflesh() 和close(),使得其具有啟動、重新整理和關閉應用上下文的能力。

在應用上下文關閉的情況下呼叫 reflesh() 即可啟動應用上下文;在應用上下文啟動的情況下呼叫 reflesh() 即可清除快取並且重新裝載配置資訊;呼叫 close() 方法則可以關閉應用上下文。 

ApplicationContext實現類

普通應用

FileSystemXMLApplicationContext

通過FileSystemXMLApplicationContext[地址]可以從檔案系統或url載入基於xml的Spring配置檔案。

應用程式碼如下:

String path = "D:/source/Test/src/main/resources/applicationcontext/bean-config.xml";

ApplicationContext context = new FileSystemXmlApplicationContext(path);
AccountService accountService = context.getBean("accountService", AccountService.class);

 

ClassPathXmlApplicationContext

通過ClassPathXmlApplicationContext[地址]可以從類路徑載入XML配置檔案。

應用程式碼如下:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationcontext/bean-config.xml");
AccountService accountService = context.getBean("accountService", AccountService.class);

 

AnnotationConfigApplicationContext

AnnotationConfigApplicationContext是在Spring 3.0中引入的(與@Configuration、@Component和JSR-330後設資料註釋等一起工作)。

應用程式碼如下:

ApplicationContext context = new AnnotationConfigApplicationContext(AccountConfig.class);
AccountService accountService = context.getBean(AccountService.class);

 

Web應用

進一步發掘,可以得到如下類圖:

解讀:

觀察其與本文前面展示的類圖之間的區別,可以發現Web應用以WebApplicationContext為主線。

 

AnnotationConfigWebApplicationContext

AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的一個基於web的變體。

Note:

從Spring 3.0開始,可以通過程式設計方式配置ApplicationContext,開發人員需要做的是實現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
  }
}

 

XmlWebApplicationContext

如果在web應用程式中使用基於XML的配置可以使用XmlWebApplicationContext;類似AnnotationConfigWebApplicationContext,可以通過實現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
  }
}

 

深度解析

Message Resolution

ApplicationContext介面通過擴充套件MessageSource介面來支援訊息解析和國際化。

 

Spring提供了兩個MessageSource實現:ResourceBundleMessageSource、StaticMessageSource。

  • StaticMessageSource

可以使用StaticMessageSource以程式設計方式向源新增訊息,它支援基本的國際化,更適合測試而不是生產環境。

  • ResourceBundleMessageSource

ResourceBundleMessageSource是MessageSource最常見的實現,它依賴於底層JDK的ResouceBundle[地址]實現;它還使用了 JDK 提供的標準訊息解析 —— MessageFormat。

案例:

@Bean
public MessageSource messageSource() {
  ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
  messageSource.setBasename("config/messages");
  return messageSource;
}
@Autowired
private MessageSource messageSource;
messageSource.getMessage("account.name", null, Locale.ENGLISH);

 

Note:

Spring提供了ReloadableResourceBundleMessageSource類[地址],它允許從任何Spring資源位置讀取檔案,並支援熱載入bundle屬性檔案。

 

Event Handling

ApplicationContext 通過擴充套件ApplicationEventPublisher讓容器擁有釋出應用上下文事件的能力;它支援內建事件,如:ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent;此外,它還支援自定義事件。

ApplicationContext 在 ApplicationEvent 類和 ApplicationListener 介面的幫助下支援事件處理:

  • 實現了 ApplicationListener 介面的 Bean 可以接收到容器事件,進而對事件進行處理
  • 在 ApplicationContext 的子類 AbstractApplicationContext 中存在一個 ApplicationEventMulticaster 變數,它儲存所有監聽器,以便在容器產生上下文事件時通知這些事件監聽器

 

ApplicationContext層次結構

ApplicationContext的層次結構提供了一種重用bean的方法,可以在child ApplicationContext中訪問在parent ApplicationContext中定義的bean。

Spring提供了指定parent ApplicationContext的方法,相關建構函式如下:

 

Note:

child ApplicationContext與parent ApplicationContext通過父/子關係相關聯;不是組合關係。

對這一概念的理解,請琢磨下面幾個case:

場景1:

Each Spring MVC webapp has one root application context and one servlet application context for each DispatcherServlet.

The root application context is the parent of each servlet application context.

Beans defined in "contextConfigLocation" (context-param in web.xml) are loaded into root application context.

Beans in <servlet-name>-servlet.xml are loaded into servlet application context.

If an EAR has multiple web apps, an EAR level application context can parent the root context of each webapp in the EAR.

資料

https://docs.spring.io/spring-framework/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-servlet


場景2:

For example, Spring Security is independent of Spring MVC and requires its configuration beans to go in the webapp context. If you want to use Spring MVC with it, then the config for that has to go into the servlet context, which has the root webapp context as its parent.


場景3:

It's possible to create separate contexts and organize them in a hierarchy in Spring Boot.

Each child context can override configuration inherited from the parent context.

The SpringApplicationBuilder class provides a fluent API to create a parent-child relationship between contexts using parent()child() and sibling() methods.

資料:

https://www.baeldung.com/spring-boot-context-hierarchy

 

Note:

BeanFactory 在初始化容器時並未例項化 Bean,直到第一次訪問某個Bean 時才例項化目標 Bean;ApplicationContext 在初始化容器時就例項化所有的單例項 Bean。

相關文章