Spring之ApplicationContext

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。

原文地址:https://www.cnblogs.com/studyLog-share/p/14957584.html