注:BeanFactory 和 ApplicationContext 这两篇比较像定义的各种解释,很多东西回过头来学习可能会更好,这里只是提了一下,如果感觉枯燥,感觉可以暂时略过。

一开始的时候,就说过,我们更多使用的还是 ApplicationContext,上一篇讲了 BeanFactory 相关的一些内容,这一篇就是关于 ApplicationContext 的,同样这些概念暂时有一个宏观认识即可,不用强行记忆,可以随着学习慢慢理解。

1. ApplicationContext 和它的继承类和接口类

image.png
和上一篇的方法一致,我们通过 IDEA 可以看到,ApplicationContext 其实继承了很多类,除了 BeanFactory 的子类外,还有一些,我们先来一起读一读它们的介绍。

1.1 ApplicationContext 本身

地址:ApplicationContext

1.1.1 它是最核心接口

Central interface to provide configuration for an application. This is read-only while the application is running, but may be reloaded if the implementation supports this.

为应用程序提供配置的中央接口。在应用程序运行时,这是只读的,但如果实现支持,可能会重新加载。

它是 Spring 最核心的中央接口,而且它提到了重新加载的机制,后面 AbstractApplicationContext 中会再提到这个概念。

1.1.2 ApplicationContext 继承多个接口以及提供的功能

An ApplicationContext provides:

  • Bean factory methods for accessing application components. Inherited from ListableBeanFactory.
  • The ability to load file resources in a generic fashion. Inherited from the ResourceLoader interface.
  • The ability to publish events to registered listeners. Inherited from the ApplicationEventPublisher interface.
  • The ability to resolve messages, supporting internationalization. Inherited from the MessageSource interface.
  • Inheritance from a parent context. Definitions in a descendant context will always take priority. This means, for example, that a single parent context can be used by an entire web application, while each servlet has its own child context that is independent of that of any other servlet.

一个ApplicationContext提供:

  • 用于访问应用程序组件的Bean工厂方法。从ListableBeanFactory继承。
  • 以通用方式加载文件资源的能力。继承自ResourceLoader接口。
  • 将事件发布到已注册侦听器的能力。继承自ApplicationEventPublisher接口。
  • 解析消息的能力,支持国际化。继承自MessageSource接口。
  • 从父上下文继承。后代上下文中的定义总是优先。这意味着,例如,一个单独的父上下文可以被整个web应用程序使用,而每个servlet都有自己独立于任何其他servlet的子上下文。

这一段主要列出了 ApplicationContext 的通过继承且提供的一些支持和能力,注意这里描述的是上下文,而不是容器,上下文的概念是大于容器的,上下文包括容器,还有动态增强,资源加载、事件监听等多方面的机制。

1.1.3 调用其它 Aware 的 bean

In addition to standard BeanFactory lifecycle capabilities, ApplicationContext implementations detect and invoke ApplicationContextAware beans as well as ResourceLoaderAware, ApplicationEventPublisherAware and MessageSourceAware beans.

除了标准的BeanFactory生命周期功能,ApplicationContext实现检测和调用ApplicationContextAware bean以及ResourceLoaderAware、ApplicationEventPublisherAware和MessageSourceAware bean。

1.2 ConfigurableApplicationContext(子接口)

地址:ConfigurableApplicationContext

1.2.1 提供了可配置的功能

SPI interface to be implemented by most if not all application contexts. Provides facilities to configure an application context in addition to the application context client methods in the ApplicationContext interface.

SPI接口将由大多数(如果不是所有的话)应用程序上下文实现。除了ApplicationContext接口中的应用程序上下文客户机方法外,还提供配置应用程序上下文的工具。

SPI 我们后面再提,而用于改变 ApplicationContext ,ConfigurableApplicationContext 中扩展了 setParent 、setEnvironment 、addBeanFactoryPostProcessor 、addApplicationListener 等方法。

1.2.2 只用于启动和关闭

Configuration and lifecycle methods are encapsulated here to avoid making them obvious to ApplicationContext client code. The present methods should only be used by startup and shutdown code.

这里封装了配置和生命周期方法,以避免它们对ApplicationContext客户机代码过于明显。目前的方法应该只被启动和关闭代码使用。

虽然它提供了一些方法,能够进行一定的配置和修改,但是最好还是只用于启动和修改,不希望被开发者调用。

1.3 EnvironmentCapable

地址:EnvironmentCapable

1.3.1 ApplicationContext 具有 EnvironmentCapable 的功能

Interface indicating a component that contains and exposes an Environment reference. All Spring application contexts are EnvironmentCapable, and the interface is used primarily for performing instanceof checks in framework methods that accept BeanFactory instances that may or may not actually be ApplicationContext instances in order to interact with the environment if indeed it is available.

它是具有获取并公开 Environment 引用的接口 所有Spring应用程序上下文都是EnvironmentCapable,该接口主要用于在框架方法中执行instanceof检查,该框架方法接受BeanFactory实例(可能是也可能不是ApplicationContext实例),以便在环境确实可用时与之交互。

这段话就是说,ApplicationContext 的任何子类,都实现了它,所以都能获取到 Environment,Environment的概念我们后面的文章会提到。

1.3.2 ConfigurableApplicationContext 可以获取 ConfigurableEnvironment

As mentioned, ApplicationContext extends EnvironmentCapable, and thus exposes a getEnvironment() method; however, ConfigurableApplicationContext redefines getEnvironment() and narrows the signature to return a ConfigurableEnvironment. The effect is that an Environment object is ‘read-only’ until it is being accessed from a ConfigurableApplicationContext, at which point it too may be configured.

如上所述,ApplicationContext扩展了EnvironmentCapable,并因此公开了getEnvironment()方法;然而,ConfigurableApplicationContext重新定义getEnvironment()并缩小签名以返回ConfigurableEnvironment。其效果是,一个Environment对象是“只读”的,直到它被从ConfigurableApplicationContext访问,此时它也可以被配置。

1.4 MessageSource

地址:MessageSource

Strategy interface for resolving messages, with support for the parameterization and internationalization of such messages. Spring provides two out-of-the-box implementations for production:

用于解析消息的策略接口,支持这类消息的参数化和国际化。 Spring为生产提供了两种开箱即用的实现:

  • ResourceBundleMessageSource:构建在标准ResourceBundle之上,共享其限制。
  • ReloadableResourceBundleMessageSource:高度可配置,特别是关于重新加载消息定义。

这一块是关于国际化的,暂时只知道这个概念就行,应用的话,在 SpringBoot 的学习中,大家肯定已经接触过。

1.5 ApplicationEventPublisher

地址:ApplicationEventPublisher

Interface that encapsulates event publication functionality. Serves as a super-interface for ApplicationContext.

封装事件发布功能的接口。 作为ApplicationContext的超级接口。

Spring 本身是支持时间监听机制的,既然 ApplicationContext 作为容器中最顶级的,所以也实现了观察者模式汇总广播器的角色,具体细节在后面事件驱动的时候再提。

1.6 ResourcePatternResolver

地址:ResourcePatternResolver

1.6.1 是ResourceLoader的扩展

Strategy interface for resolving a location pattern (for example, an Ant-style path pattern) into Resource objects. This is an extension to the ResourceLoader interface. A passed-in ResourceLoader (for example, an ApplicationContext passed in via ResourceLoaderAware when running in a context) can be checked whether it implements this extended interface too.

将位置模式(例如,ant风格的路径模式)解析为Resource对象的策略接口。 这是ResourceLoader接口的扩展。一个传入的ResourceLoader(例如,一个在上下文中运行时通过ResourceLoaderAware传入的ApplicationContext)可以检查它是否也实现了这个扩展的接口。

1.6.2 的实现方式有多种

PathMatchingResourcePatternResolver是一个独立的实现,可以在ApplicationContext之外使用,也可以被resourceearraypropertyeditor用于填充资源数组bean属性。

PathMatchingResourcePatternResolver is a standalone implementation that is usable outside an ApplicationContext, also used by ResourceArrayPropertyEditor for populating Resource array bean properties.

1.6.3 支持的Ant路径模式匹配

Can be used with any sort of location pattern (e.g. “/WEB-INF/*-context.xml”): Input patterns have to match the strategy implementation. This interface just specifies the conversion method rather than a specific pattern format.

可以用于任何类型的位置模式(例如:”/WEB-INF/*-context.xml”):输入模式必须匹配策略实现。这个接口只指定转换方法,而不是特定的模式格式。

1.6.4 可以匹配类路径下的文件

This interface also suggests a new resource prefix “classpath*:” for all matching resources from the class path. Note that the resource location is expected to be a path without placeholders in this case (e.g. “/beans.xml”); JAR files or different directories in the class path can contain multiple files of the same name.

该接口还建议为类路径中的所有匹配资源添加一个新的资源前缀“classpath*:”。注意,在这种情况下,资源位置应该是一个没有占位符的路径(例如。“/它指明”);JAR文件或类路径中的不同目录可以包含多个同名文件。

2. ApplicationContext 的实现类

image.png

2.1 AbstractApplicationContext

地址:AbstractApplicationContext
这个类是 ApplicationContext 的一个非常核心的类,其中定义了很多上下文的功能和特性。

2.1.1 只构建功能抽象

Abstract implementation of the ApplicationContext interface. Doesn’t mandate the type of storage used for configuration; simply implements common context functionality. Uses the Template Method design pattern, requiring concrete subclasses to implement abstract methods.

ApplicationContext接口的抽象实现。不强制要求用于配置的存储类型;简单地实现公共上下文功能。使用模板方法设计模式,需要具体的子类来实现抽象方法。

这里提到了 AbstractApplicationContext 只是为了规范,而具体的实现由子类实现

2.1.2 可识别特殊 bean

In contrast to a plain BeanFactory, an ApplicationContext is supposed to detect special beans defined in its internal bean factory: Therefore, this class automatically registers BeanFactoryPostProcessors, BeanPostProcessors, and ApplicationListeners which are defined as beans in the context.

与普通的BeanFactory相反,ApplicationContext应该检测在其内部bean工厂中定义的特殊bean:因此,这个类自动注册了在上下文中定义为bean的BeanFactoryPostProcessors、BeanPostProcessors和ApplicationListeners。

因为 ApplicationContext 相比较 BeanFactory 而言,它更加强大,例如后置处理器,监听器等等组件,而这些组件本质上也是一个一个 bean,但是 ApplicationContext 就应该可以区分出这些特殊的 bean,并且使它们发挥功能。

2.1.3 可以转换为多种类型

A MessageSource may also be supplied as a bean in the context, with the name “messageSource”; otherwise, message resolution is delegated to the parent context. Furthermore, a multicaster for application events can be supplied as an “applicationEventMulticaster” bean of type ApplicationEventMulticaster in the context; otherwise, a default multicaster of type SimpleApplicationEventMulticaster will be used.

MessageSource也可以在上下文中作为bean提供,命名为“MessageSource”;否则,消息解析被委托给父上下文。此外,应用事件的多播器可以作为applicationEventMulticaster类型的bean在上下文中提供;否则,将使用SimpleApplicationEventMulticaster类型的默认multicaster。

ApplicationContext 实现了国际化、时间广播器,它也会把自己当做 Bean,以支持不同类型的组件注入需要。

2.1.4 提供默认的加载资源文件策略

Implements resource loading by extending DefaultResourceLoader. Consequently treats non-URL resource paths as class path resources (supporting full class path resource names that include the package path, e.g. “mypackage/myresource.dat”), unless the DefaultResourceLoader.getResourceByPath(java.lang.String) method is overridden in a subclass.

通过扩展DefaultResourceLoader实现资源加载。因此,将非url资源路径视为类路径资源(支持包含包路径的完整类路径资源名,例如。除非DefaultResourceLoader.getResourceByPath(java.lang.String)方法在子类中被重写。

AbstractApplicationContext 加载资源文件是直接继承了 DefaultResourceLoader 的这种策略,即从类路径下加载,不过如果在 Web 项目中,它还可以从 ServletContext 中加载(扩展的子类 ServletContextResourceLoader 等)。

2.2 GenericApplicationContext

它是一个注解驱动 IOC 的普通类,但是实现了 ApplicationContext 基本的所有功能了。
地址:GenericApplicationContext

2.2.1 组合了DefaultListableBeanFactory

Generic ApplicationContext implementation that holds a single internal DefaultListableBeanFactory instance and does not assume a specific bean definition format. Implements the BeanDefinitionRegistry interface in order to allow for applying any bean definition readers to it.

通用的ApplicationContext实现,保存单个内部DefaultListableBeanFactory实例,并且不采用特定的bean定义格式。实现BeanDefinitionRegistry接口,以便对其应用任何bean定义读取器。

这一段有一个重要的点,因为它区中组合了一个 DefaultListableBeanFactory,即可以知道 ApplicationContext 不是继承 BeanFactory 而是组合。

2.2.2 借助BeanDefinitionRegistry处理特殊Bean

Typical usage is to register a variety of bean definitions via the BeanDefinitionRegistry interface and then call AbstractApplicationContext.refresh() to initialize those beans with application context semantics (handling ApplicationContextAware, auto-detecting BeanFactoryPostProcessors, etc).

典型的用法是通过BeanDefinitionRegistry接口注册各种bean定义,然后调用AbstractApplicationContext.refresh()来用应用上下文语义初始化那些bean(处理ApplicationContextAware,自动检测BeanFactoryPostProcessors,等等)。

2.2.3 只能刷新一次

In contrast to other ApplicationContext implementations that create a new internal BeanFactory instance for each refresh, the internal BeanFactory of this context is available right from the start, to be able to register bean definitions on it. AbstractApplicationContext.refresh() may only be called once.

与为每次刷新创建一个新的内部BeanFactory实例的其他ApplicationContext实现不同,此上下文的内部BeanFactory从一开始就可用,以便能够在其上注册bean定义。refresh()只能被调用一次。

因为上面提到了,DefaultListableBeanFactory 组合了一个 BeanFactory,所以这个 BeanFactory 是在它的构造方法中就初始化了,所以运行时就不允许被重复刷新了。

不过下面还有与他相反的例子。

2.2.4 的替代方案是用xml

For the typical case of XML bean definitions, simply use ClassPathXmlApplicationContext or FileSystemXmlApplicationContext, which are easier to set up - but less flexible, since you can just use standard resource locations for XML bean definitions, rather than mixing arbitrary bean definition formats. The equivalent in a web environment is XmlWebApplicationContext.

对于XML bean定义的典型情况,只需使用ClassPathXmlApplicationContext或FileSystemXmlApplicationContext,它们更容易设置——但不够灵活,因为您可以仅为XML bean定义使用标准的资源位置,而不是混合任意的bean定义格式。在web环境中等效的是XmlWebApplicationContext。

这段提到了,即使注解驱动的 IOC 容器也可以导入 xml,但是如果大多数都是 xml 配置,还是建议通过 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext,所以我们可以知道,注解驱动的开发方法,修改配置就需要重新编译,而 xml 驱动的直接修改就行,使用时自己权衡一下。

2.2.5 不支持特殊Bean定义的可刷新读取

For custom application context implementations that are supposed to read special bean definition formats in a refreshable manner, consider deriving from the AbstractRefreshableApplicationContext base class.

对于自定义应用程序上下文实现,这些实现应该以可刷新的方式读取特殊的bean定义格式,考虑从AbstractRefreshableApplicationContext基类派生。

2.3 AbstractRefreshableApplicationContext

地址:AbstractRefreshableApplicationContext

2.3.1 支持多次刷新

Base class for ApplicationContext implementations which are supposed to support multiple calls to AbstractApplicationContext.refresh(), creating a new internal bean factory instance every time. Typically (but not necessarily), such a context will be driven by a set of config locations to load bean definitions from.

ApplicationContext实现的基类,应该支持对AbstractApplicationContext.refresh()的多次调用,每次都创建一个新的内部bean工厂实例。通常(但不一定),这样的上下文将由一组用于从其中加载bean定义的配置位置驱动。

2.3.2 刷新的核心是加载Bean定义信息

The only method to be implemented by subclasses is loadBeanDefinitions(org.springframework.beans.factory.support.DefaultListableBeanFactory), which gets invoked on each refresh. A concrete implementation is supposed to load bean definitions into the given DefaultListableBeanFactory, typically delegating to one or more specific bean definition readers.

由子类实现的唯一方法是loadBeanDefinitions,每次刷新时都会调用它。具体的实现应该将bean定义加载到给定的DefaultListableBeanFactory中,通常委托给一个或多个特定的bean定义阅读器。

2.3.3 额外扩展了Web环境的功能

Note that there is a similar base class for WebApplicationContexts. AbstractRefreshableWebApplicationContext provides the same subclassing strategy, but additionally pre-implements all context functionality for web environments. There is also a pre-defined way to receive config locations for a web context.

注意,WebApplicationContexts也有一个类似的基类。abstractrefresshablewebapplicationcontext提供了相同的子类化策略,但是额外地为web环境预先实现了所有上下文功能。还有一个预定义的方式来接收web上下文的配置位置。

2.3.4 几个重要的最终实现类

Concrete standalone subclasses of this base class, reading in a specific bean definition format, are ClassPathXmlApplicationContext and FileSystemXmlApplicationContext, which both derive from the common AbstractXmlApplicationContext base class; AnnotationConfigApplicationContext supports @Configuration-annotated classes as a source of bean definitions.

这个基类的具体的独立子类,以特定的bean定义格式读取,是ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,它们都派生自公共的AbstractXmlApplicationContext基类;AnnotationConfigApplicationContext支持带@ configuration注释的类作为bean定义的源。

2.4 AbstractRefreshableConfigApplicationContext

地址:AbstractRefreshableConfigApplicationContext

AbstractRefreshableApplicationContext subclass that adds common handling of specified config locations. Serves as base class for XML-based application context implementations such as ClassPathXmlApplicationContext and FileSystemXmlApplicationContext, as well as XmlWebApplicationContext.

子类增加了对指定配置位置的通用处理。作为基于xml的应用程序上下文实现的基类,如ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,以及XmlWebApplicationContext。

2.5 AbstractXmlApplicationContext

地址:AbstractXmlApplicationContext

2.5.1 它已具备基本全部功能

onvenient base class for ApplicationContext implementations, drawing configuration from XML documents containing bean definitions understood by an XmlBeanDefinitionReader.

ApplicationContext实现的方便基类,从包含XmlBeanDefinitionReader理解的bean定义的XML文档中绘制配置。

2.5.2 它中已经含有loadBeanDefinitions的实现

Subclasses just have to implement the getConfigResources() and/or the AbstractRefreshableConfigApplicationContext.getConfigLocations() method. Furthermore, they might override the DefaultResourceLoader.getResourceByPath(java.lang.String) hook to interpret relative paths in an environment-specific fashion, and/or AbstractApplicationContext.getResourcePatternResolver() for extended pattern resolution.

子类只需要实现getConfigResources()和/或abstractrefresshableconfigapplicationcontext . getconfiglocations()方法。此外,它们可能会覆盖DefaultResourceLoader.getResourceByPath(java.lang.String)钩子来以特定于环境的方式解释相对路径,以及/或AbstractApplicationContext.getResourcePatternResolver()来进行扩展的模式解析。

2.6 ClassPathXmlApplicationContext

地址:ClassPathXmlApplicationContext

2.6.1 它是一个最终落地实现

Standalone XML application context, taking the context definition files from the class path, interpreting plain paths as class path resource names that include the package path (e.g. “mypackage/myresource.txt”). Useful for test harnesses as well as for application contexts embedded within JARs.

独立的XML应用程序上下文,从类路径中获取上下文定义文件,将普通路径解释为类路径资源名,其中包括包路径(例如。“mypackage / myresource.txt”)。对于测试工具和嵌入在jar中的应用程序上下文都很有用。

2.6.2 它使用Ant模式声明配置文件路径

The config location defaults can be overridden via AbstractRefreshableConfigApplicationContext.getConfigLocations(), Config locations can either denote concrete files like “/myfiles/context.xml” or Ant-style patterns like “/myfiles/*-context.xml” (see the AntPathMatcher javadoc for pattern details).

配置位置的默认值可以被abstractrefresshableconfigapplicationcontext . getconfiglocations()覆盖,配置位置可以表示具体的文件,如“/myfiles/context.xml”或ant风格的模式,如“/myfiles/*-context.xml”(参见AntPathMatcher javadoc的模式细节)。

2.6.3 它解析的配置文件有先后之分

Note: In case of multiple config locations, later bean definitions will override ones defined in earlier loaded files. This can be leveraged to deliberately override certain bean definitions via an extra XML file.

注意:在有多个配置位置的情况下,后面的bean定义将覆盖前面加载文件中定义的。可以利用这一点,通过额外的XML文件有意覆盖某些bean定义。

2.6.4 可组合灵活使用

This is a simple, one-stop shop convenience ApplicationContext. Consider using the GenericApplicationContext class in combination with an XmlBeanDefinitionReader for more flexible context setup.
这是一个简单的一站式商店方便的ApplicationContext。考虑将GenericApplicationContext类与XmlBeanDefinitionReader结合使用,以实现更灵活的上下文设置。

2.7 AnnotationConfigApplicationContext

地址:AnnotationConfigApplicationContext

2.7.1 是一个最终落地实现

Standalone application context, accepting component classes as input — in particular @Configuration-annotated classes, but also plain @Component types and JSR-330 compliant classes using javax.inject annotations.

独立的应用程序上下文,接受组件类作为输入——特别是带@ configuration注释的类,但也可以使用javax接受普通的@Component类型和JSR-330兼容的类。注入注解。

2.7.2 解析的配置类也有先后之分

Allows for registering classes one by one using register(Class…) as well as for classpath scanning using scan(String…). In case of multiple @Configuration classes, @Bean methods defined in later classes will override those defined in earlier classes. This can be leveraged to deliberately override certain bean definitions via an extra @Configuration class.

允许使用register(Class…)一个接一个注册类,也允许使用scan(String…)扫描类路径。 在有多个@Configuration类的情况下,后面类中定义的@Bean方法将覆盖前面类中定义的方法。可以利用这一点,通过额外的@Configuration类有意覆盖某些bean定义。