这些类主要是了解过一遍,大致了解整个容器的集成体系,方便后续研究 Spring 容器启动流程。
1. Spring 容器
org.springframework.context.ApplicationContext
接口代表 Spring IoC 容器,主要负责 Bean 的实例化、配置、装配,简而言之,Spring IoC 容器是管理这些 Bean 的(这里所说的 Bean 指的是组成你的应用程序中的对象,并且这些对象被 Spring 所管理)。容器如何知道哪些对象要进行实例化、配置和装配的呢?是通过读取配置文件元数据来达到这个效果的,配置文件元数据是用 XML 配置、Java 注解和 JavaConfig 来表示的。这使得作为程序员的我们,只需要向 Spring 容器提供配置元数据,Spring 容器就能在我们的应用中实例化、配置和装配这些对象。org.springframework.beans
和 org.springframework.context
包是 Spring IoC 容器的基础。Spring 提供了很多 ApplicationContext
接口的实现。在单独的应用中,创建 ClassPathXmlApplicationContext
和 FileSystemXmlApplicationContext
的实例是非常常用的做法。示例如下:
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) ac.getBean("hello");
hello.sayHello();
然而在大部分的应用场景中,不需要实例化一个或者多个 Spring IoC 容器的实例。例如在 Web 应用的场景下,只需要在 web.xml 中创建 7 行样板配置的代码如下:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</paramvalue>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
2. ApplicationContext 设计解析
为了方便对 ApplicationContext
接口的层次结构有一个大概的认识,下面使用 IDEA 来生成 ApplicationContext
的继承关系图。
从上图就能很清楚的看出 ApplicationContext
继承的接口分为五类:
BeanFactory
:提供了能够管理任何对象的高级配置机制,这个接口是 Spring 框架中比较重要的一个接口。ListableBeanFactory
:从该接口的名字就能知道,该接口除了拥有BeanFactory
的功能外,该接口还有能列出 Factory 中所有 Bean 的实例的能力。HierarchicalBeanFactory
:该接口除了拥有BeanFactory
的功能外,还提供了 BeanFactory 分层的机制,查找 Bean 的时候,除了在自身 BeanFactory 查找外,如果没有查找到,还会在父级 BeanFactory 进行查找。MessageSource
:消息资源的处理,用于国际化。ApplicationEventPublisher
:用于处理事件发布机制。EnvironmentCapable
:提供了Environment
的访问能力。ResourceLoader
:用于加载资源的策略接口(例如类路径下的资源、系统文件下的资源等等)。ResourcePatternResolver
:用于将位置模式(例如 Maven 风格的路径模式)解析成资源对象的策略接口。classpath*:
前缀能匹配所有类路径下的资源。
先看一下在 ApplicationContext
中定义的方法:
String getId(); // 获取ApplicationContext的唯一id
String getApplicationName(); // 该上下文所属的已经部署了的应用的名字,默认为""
String getDisplayName(); // 友好的展示名字
long getStartupDate(); // 该上下文第一次加载的时间
ApplicationContext getParent(); // 获取父级ApplicationContext
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
前四个方法用于获取该 ApplicationContext
的一些基本信息,getAutowireCapableBeanFactory()
用于暴露 AutowireCapableBeanFactory
的功能,这通常不是提供给用于代码使用的,除非你想要在应用上下文的外面初始化 Bean 的实例,关于 AutowireCapableBeanFactory
后面会有更加详细的解析。
2.1 BeanFactory
这是用于访问 Spring Bean 容器的根接口,该接口由包含许多 Bean 定义的对象实现,每个 Bean 定义都由一个 String
名称唯一标识。根据 Bean 定义,工厂将返回被包含对象的独立实例(Prototype 设计模式),或单个共享实例 (一个比单例设计模式更好的选择,在单例设计模式中,实例是工厂范围内的单例)。
/*
* 在之前注解驱动开发中介绍 FactoryBean 的时候,我们看到了这个 Bean 的 name 对应的不是工厂 Bean,
* 而是工厂 Bean产生的实例,而工厂 Bean 的 name 需要前缀加上 &,就是在这里定义的。
*/
String FACTORY_BEAN_PREFIX = "&";
// 获取 Bean
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
// 获取 Bean 的提供者(对象工厂)
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
boolean containsBean(String name); // 是否包含指定名字的 Bean
boolean isSingleton(String name) throws NoSuchBeanDefinitionException; // 是否为单例
boolean isPrototype(String name) throws NoSuchBeanDefinitionException; // 是否为原型
// 指定名字的 Bean 是否和指定的类型匹配
boolean isTypeMatch(String name, ResolvableType typeToMatch);
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
Class<?> getType(String name) throws NoSuchBeanDefinitionException; // 获取指定名字的 Bean 的类型
String[] getAliases(String name); // 获取指定名字的 Bean 的所有别名
这些方法大致可以分为三类:
-
getBean()
方法用于获取匹配的 Bean 的实例对象(有可能是 Singleton 或者 Prototype 的),如果没有找到匹配的 Bean 则抛出BeansException
子类的异常。如果在当前的工厂实例中没有找到匹配的 Bean,会在父级的工厂中进行查找。带有args
参数的getBean()
方法,允许显式的去指定构造器或者工厂方法的参数,会覆盖了在 Bean 的定义中定义的参数,这仅仅在创建一个新的实例的时候才起作用,而在获取一个已经存在的实例是不起作用的。 -
getBeanProvider()
方法用于获取指定 Bean 的提供者,可以看到它返回的是一个ObjectProvider
,其父级接口是ObjectFactory
。首先来看一下ObjectFactory
,它是一个对象的实例工厂,只有一个方法:T getObject() throws BeansException;
调用这个方法返回的是一个对象的实例。此接口通常用于封装一个泛型工厂,在每次调用的时候返回一些目标对象新的实例。
ObjectFactory
和FactoryBean
是类似的,只不过FactoryBean
通常被定义为BeanFactory
中的服务提供者(SPI)实例,而ObjectFactory
通常是以 API 的形式提供给其他的 Bean。简单的来说,ObjectFactory
一般是提供给开发者使用的,FactoryBean
一般是提供给BeanFactory
使用的。ObjectProvider
继承ObjectFactory
,特为注入点而设计,允许可选择性的编程和宽泛的非唯一性的处理。在 Spring 5.1 的时候,该接口从Iterable
扩展,提供了对Stream
的支持。该接口的方法如下:public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> { // 返回指定类型的 Bean, 如果容器中不存在, 抛出 NoSuchBeanDefinitionException 异常 // 如果容器中有多个此类型的 Bean, 抛出 NoUniqueBeanDefinitionException 异常 T getObject(Object... args) throws BeansException; // 如果指定类型的 Bean 注册到容器中, 返回 Bean 实例, 否则返回 null @Nullable T getIfAvailable() throws BeansException; // 如果返回对象不存在,则进行回调,回调对象由 Supplier 传入 default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException { T dependency = getIfAvailable(); return (dependency != null ? dependency : defaultSupplier.get()); } // 消费对象的一个实例(可能是共享的或独立的),如果存在通过 Consumer 回调消耗目标对象。 default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException { T dependency = getIfAvailable(); if (dependency != null) { dependencyConsumer.accept(dependency); } } // 如果不可用或不唯一(没有指定 @primary )则返回 null。否则,返回对象。 @Nullable T getIfUnique() throws BeansException; // 如果存在唯一对象,则调用 Supplier 的回调函数 default T getIfUnique(Supplier<T> defaultSupplier) throws BeansException { T dependency = getIfUnique(); return (dependency != null ? dependency : defaultSupplier.get()); } // 如果存在唯一对象,则消耗掉该对象 default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException { T dependency = getIfUnique(); if (dependency != null) { dependencyConsumer.accept(dependency); } } // 返回符合条件的对象的 Iterator,没有特殊顺序保证(一般为注册顺序) @Override default Iterator<T> iterator() { return stream().iterator(); } // 返回符合条件对象的连续的 Stream,没有特殊顺序保证(一般为注册顺序) default Stream<T> stream() { throw new UnsupportedOperationException("Multi element access not supported"); } // 返回符合条件对象的连续的 Stream。在标注 Spring 应用上下文中采用 @Order 注解或实现 Order 接口的顺序 default Stream<T> orderedStream() { throw new UnsupportedOperationException("Ordered element access not supported"); } }
这些接口是分为两类:
-
一类是获取单个对象,
getIfAvailable()
方法用于获取可用的 Bean(没有则返回null
),getIfUnique()
方法用于获取唯一的 Bean(如果 Bean 不是唯一的或者没有标记为@Primary
的 Bean 返回null
)。getIfAvailable(Supplier<T> defaultSupplier)
和getIfUnique(Supplier<T> defaultSupplier)
,如果没有获取到 Bean,则返回defaultSupplier
提供的默认值,ifAvailable(Consumer<T> dependencyConsumer)
和ifUnique(Consumer<T> dependencyConsumer)
提供了以函数式编程的方式去消费获取到的 Bean。 -
另一类是获取多个对象,
stream()
方法返回连续的Stream
,不保证 Bean 的顺序(通常是 Bean 的注册顺序)。orderedStream()
方法返回连续的Stream
,预先会根据工厂的公共排序比较器进行排序,一般是根据org.springframework.core.Ordered
的约定进行排序。
-
-
其他的是一些工具性的方法:
- 通过名字判断是否包含指定 Bean 的定义的
containsBean(String name)
方法 - 判断是单例和原型的
isSingleton(String name)
和isPrototype(String name)
方法 - 判断给定 Bean 的名字是否和类型匹配的
isTypeMatch
方法 - 根据 Bean 的名字来获取其类型的
getType(String name)
方法 - 根据 Bean 的名字来获取其别名的
getAliases(String name)
方法
- 通过名字判断是否包含指定 Bean 的定义的
或许你已经注意到了,有两个方法含有类型是 ResolvableType
的参数,那么 ResolvableType
是什么呢?假如说你要获取泛型类型的Bean:MyBean<TheType>
,根据 Class 来获取,肯定是满足不了要求的,泛型在编译时会被擦除。使用 ResolvableType
就能满足此需求,代码如下:
ResolvableType type = ResolvableType.forClassWithGenerics(MyType.class, TheType.class);
ObjectProvider<MyType<TheType>> op = applicationContext.getBeanProvider(type);
MyType<TheType> bean = op.getIfAvailable()
简单的来说,ResolvableType
是对 Java java.lang.reflect.Type
的封装,并且提供了一些访问该类型的其他信息的方法(例如父类, 泛型参数,该类)。从成员变量、方法参数、方法返回类型、类来构建 ResolvableType
的实例。
2.2 ListableBeanFactory
ListableBeanFactory
接口可以枚举所有 Bean 实例,而不是像客户端请求的那样逐个尝试按名称进行 Bean 查找。下面给出该接口中的所有方法:
boolean containsBeanDefinition(String beanName); // 是否包含给定名字的 bean definition
int getBeanDefinitionCount(); // 工厂中 bean definition 的数量
String[] getBeanDefinitionNames(); // 返回该工厂中定义的所有 Bean 的名称
// 返回指定 Bean 的提供程序,允许延迟按需检索实例,包括可用性和惟一性选项
<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType, boolean allowEagerInit);
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType, boolean allowEagerInit);
// 获取指定类型的 Bean 的名字
String[] getBeanNamesForType(ResolvableType type);
String[] getBeanNamesForType(Class<?> type);
String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
// 获取所有使用提供的注解进行标注的 Bean 的名字
String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
// 查找指定 Bean 中的所有指定的注解(会考虑接口和父类中的注解)
<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) throws NoSuchBeanDefinitionException;
// 根据指定的类型来获取所有的 Bean
<T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
<T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) throws BeansException;
// 获取所有使用提供的注解进行标注了的 Bean
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
上面的这些方法都不考虑祖先工厂中的 Bean,只会考虑在当前工厂中定义的 Bean。
- 前几个方法用于获取 Bean 的一些信息
- 最后的三个方法用于获取所有满足条件的 Bean,返回结果
Map
中的键为 Bean 的名字,值为 Bean 的实例。这些方法都会考虑通过FactoryBean
创建的 Bean,这也意味着FactoryBean
会被初始化。为什么这里的三个方法不返回List
?Map
不光包含这些Bean
的实例,而且还包含 Bean 的名字,而List
只包含 Bean 的实例。也就是说Map
比List
更加的通用。
2.3 HierarchicalBeanFactory
HierarchicalBeanFactory
接口定义了 BeanFactory 之间的分层结构,ConfigurableBeanFactory
中的 setParentBeanFactory()
方法能设置父级的 BeanFactory,下面列出了 HierarchicalBeanFactory
中定义的方法:
BeanFactory getParentBeanFactory(); // 获取父级的 BeanFactory
boolean containsLocalBean(String name); // 本地的工厂是否包含指定名字的 Bean
这两个方法都比较直接明了,getParentBeanFactory()
方法用于获取父级 BeanFactory。containsLocalBean()
用于判断本地的工厂是否包含指定的 Bean,忽略在祖先工厂中定义的 Bean。
2.4 MessageSource
MessageSource
主要用于消息的国际化,下面是该接口中的方法定义:
// 获取消息
String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
以上的三个方法都是用于获取消息的,第一个方法提供了默认消息,第二个方法如果没有获取到指定的消息会抛出异常,第三个方法中的 MessageSourceResolvable
参数是对代码、参数值、默认值的一个封装。
2.5 ApplicationEventPublisher
ApplicationEventPublisher
接口封装了事件发布功能,提供 Spring 中事件的机制。接口中的方法定义如下:
// 发布事件
void publishEvent(ApplicationEvent event);
void publishEvent(Object event);
第一个方法用于发布特定于应用程序事件。第二个方法能发布任意的事件,如果事件不是 ApplicationEvent
,那么会被包裹成 PayloadApplicationEvent
事件。
2.6 EnvironmentCapable
EnvironmentCapable
提供了访问Environment
的能力,该接口只有一个方法:
Environment getEnvironment();
Environment
表示当前正在运行的应用的环境变量,它分为两个部分:profiles 和 properties。它的父级接口 PropertyResolver
提供了 property 的访问能力。
2.7 ResourceLoader 和 ResourcePatternResolver
先来看一下 ResourceLoader
,该接口是用来加载资源(例如类路径或者文件系统中的资源)的策略接口。该接口中的方法如下:
// 伪 URL 前缀,用于从类路径加载:" classpath:"。
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
Resource getResource(String location); // 根据指定的位置获取资源
ClassLoader getClassLoader(); // 获取该资源加载器所使用的类加载器
该接口只有简单明了的两个方法,一个是用来获取指定位置的资源,一个用于获取资源加载器所使用的类加载器。Resource
是从实际类型的底层资源(例如文件、类路径资源)进行抽象的资源描述符。先看下 Resource
中的方法:
boolean exists(); // 资源实际上是否存在
boolean isReadable(); // 资源是否可读
boolean isOpen(); // 检查资源是否为打开的流
boolean isFile(); // 资源是否为文件系统上的一个文件
URL getURL() throws IOException; // 获取 url
URI getURI() throws IOException; // 获取 URI
File getFile() throws IOException; // 获取文件
ReadableByteChannel readableChannel() throws IOException; // 获取 ReadableByteChannel
long contentLength() throws IOException; // 资源的内容的长度
long lastModified() throws IOException; // 资源的最后修改时间
Resource createRelative(String relativePath) throws IOException; // 相对于当前的资源创建一个新的资源
String getFilename(); // 获取资源的文件名
String getDescription(); // 获取资源的描述信息
Resource
的父级接口 InputStreamSource
,可以简单的理解为 InputStream
的来源,只有一个方法,如下:
InputStream getInputStream() throws IOException; // 获取输入流
接下来在来看一下 ResourcePatternResolver
,该接口用于解析一个位置模式(例如 Ant 风格的路径模式),该接口只有一个方法,如下:
// 类路径中所有匹配资源的伪 URL 前缀:" classpath*:"
// 这与 ResourceLoader 的类路径 URL 前缀不同,因为它检索给定名称的所有匹配资源
// classpath:只会到你的class路径中查找找文件
// classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
// 将给定的位置模式解析成资源对象
Resource[] getResources(String locationPattern) throws IOException;
2.8 summary
BeanFactory
及其子类的功能是 IoC 容器对 Bean 的配置和管理ResourceLoader
和Resource
功能是对配置元数据的读取解析ApplicationEventPublisher
的功能是使用事件机制在 IoC 容器初始化、摧毁的时候,执行一些切面操作
3. BeanFactory 常见实现
可以看到 BeanFactory
直接的子接口主要分为三个:
HierarchicalBeanFactory
ListableBeanFactory
AutowireCapableBeanFactory
有些已经介绍过了,下面介绍其余的接口和类
3.1 AutowireCapableBeanFactory
该接口提供了对现有 Bean 进行自动装配的能力,设计目的不是为了用于一般的应用代码中,对于一般的应用代码应该使用 BeanFactory
和 ListableBeanFactory
。其他框架的代码集成可以利用这个接口去装配和填充现有的 Bean 的实例,但是 Spring 不会控制这些现有 Bean 的生命周期。你也许注意到了 ApplicationContext
中的 getAutowireCapableBeanFactory()
能获取到 AutowireCapableBeanFactory
的实例。同样,也能实现 BeanFactoryAware
接口来接收 BeanFactory
(应用程序上下暴露的内部使用的 BeanFactory
)的实例,然后将其转换成 AutowireCapableBeanFactory
。这个类的概览如下:
下面看看接口的源码:
// 定义了 Bean 的装配策略
int AUTOWIRE_NO = 0; // 不进行装配
int AUTOWIRE_BY_NAME = 1; // 根据名字进行装配
int AUTOWIRE_BY_TYPE = 2; // 根据类型进行装配
int AUTOWIRE_CONSTRUCTOR = 3; // 根据构造函数进行装配
@Deprecated
int AUTOWIRE_AUTODETECT = 4; // Spring3.0 已经过时的方法,通过省视 Bean 来决定适当的装载策略
// Spring 5.1 后增加,原始实例的后缀,例如"com.mypackage.MyClass.ORIGINAL",强制返回给定的实例(没有代理)
String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";
//-------------------------------------------------------------------------
// Typical methods for creating and populating external bean instances
//-------------------------------------------------------------------------
/*
* Fully create a new bean instance of the given class.
* Performs full initialization of the bean, including all applicable BeanPostProcessors.
*/
<T> T createBean(Class<T> beanClass) throws BeansException;
/*
* Populate the given bean instance through applying after-instantiation callbacks and
* bean property post-processing
*/
void autowireBean(Object existingBean) throws BeansException;
/*
* Configure the given raw bean: autowiring bean properties, applying bean property values,
* applying factory callbacks such as setBeanName and setBeanFactory, and also applying all
* bean post processors (including ones which might wrap the given raw bean).
*/
Object configureBean(Object existingBean, String beanName) throws BeansException;
//-------------------------------------------------------------------------
// Specialized methods for fine-grained control over the bean lifecycle
//-------------------------------------------------------------------------
/*
* 使用指定的自动装配策略完全创建给定类的新 Bean 实例,这里支持该接口中定义的所有常量。
* Performs full initialization of the bean, including all applicable BeanPostProcessors.
* This is effectively a superset of what autowire provides, adding initializeBean behavior.
*/
Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
/*
* Instantiate a new bean instance of the given class with the specified autowire strategy.
* All constants defined in this interface are supported here. Can also be invoked with AUTOWIRE_NO
* in order to just apply before-instantiation callbacks (e.g. for annotation-driven injection).
*/
Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
/*
* Autowire the bean properties of the given bean instance by name or type. Can also be invoked
* with AUTOWIRE_NO in order to just apply after-instantiation callbacks
*/
void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck) throws BeansException;
/*
* Apply the property values of the bean definition with the given name to the given bean instance.
* The bean definition can either define a fully self-contained bean, reusing its property values,
* or just property values meant to be used for existing bean instances.
*
* This method does not autowire bean properties; it just applies explicitly defined property values.
* Use the autowireBeanProperties method to autowire an existing bean instance.
*/
void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
/*
* Initialize the given raw bean, applying factory callbacks such as setBeanName and setBeanFactory,
* also applying all bean post processors (including ones which might wrap the given raw bean).
*
* Note that no bean definition of the given name has to exist in the bean factory. The passed-in
* bean name will simply be used for callbacks but not checked against the registered bean definitions.
*/
Object initializeBean(Object existingBean, String beanName) throws BeansException;
/*
* Apply BeanPostProcessors to the given existing bean instance, invoking their
* postProcessBeforeInitialization methods. The returned bean instance may be a
* wrapper around the original.
*/
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException;
/*
* Apply BeanPostProcessors to the given existing bean instance,
* invoking their postProcessAfterInitialization methods. The returned bean instance
* may be a wrapper around the original.
*/
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException;
/*
* Destroy the given bean instance (typically coming from createBean), applying the
* org.springframework.beans.factory.DisposableBean contract as well as registered
* DestructionAwareBeanPostProcessors.
*/
void destroyBean(Object existingBean);
//-------------------------------------------------------------------------
// Delegate methods for resolving injection points
//-------------------------------------------------------------------------
/*
* Resolve the bean instance that uniquely matches the given object type, if any, including its
* bean name.
* This is effectively a variant of getBean(Class) which preserves the bean name of the matching
* instance.
*/
<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;
/*
* Resolve a bean instance for the given bean name, providing a dependency descriptor for exposure
* to target factory methods.
*/
Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;
//-------------------------------------------------------------------------
// Resolve the specified dependency against the beans defined in this factory.
//-------------------------------------------------------------------------
Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName) throws BeansException;
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
3.2 ConfigurableBeanFactory
ConfigurableBeanFactory
提供了 Bean 工厂的配置机制(除了 BeanFactory
接口中的 Bean 的工厂的客户端方法)。该BeanFactory 接口不适用于一般的应用代码中,应该使用 BeanFactory
和 ListableBeanFactory
的方法。该扩展接口仅仅用于内部框架的使用,并且是对 Bean 工厂配置方法的特殊访问。
ConfigurableBeanFactory
继承自 HierarchicalBeanFactory
和 SingletonBeanRegistry
,下面先看下SingletonBeanRegistry
:
SingletonBeanRegistry
是为了共享的 Bean 的实例而定义的注册器,以统一的方式暴露单例管理机制。下面是在此接口中定义的方法:
// 在 Bean 的注册器中以给定的 Bean 的名字将给定的现存对象注册为单例
void registerSingleton(String beanName, Object singletonObject);
// 根据给定的 Bean 的名字来获取单例 Bean,可能为 null
Object getSingleton(String beanName);
// 是否包含给定名字的单例 Bean
boolean containsSingleton(String beanName);
// 获取所有在注册器中注册的单例 Bean的名字
String[] getSingletonNames();
// 获取所有在注册器中注册的单例 Bean的数量
int getSingletonCount();
// 获取在这个注册器中使用的单例的 mutex(用于外部协同)
Object getSingletonMutex();
需要注意的是使用 registerSingleton
方法注册的单例 Bean,不会执行任何的初始化回调函数(尤其不会调用 InitializingBean
的 afterPropertiesSet
方法),同样也不会接收任何的 destroy 回调函数。如果需要接收初始化和摧毁回调函数,请注册 Bean Definition 而不是现存的实例对象。
接下来看下 ConfigurableBeanFactory
中定义的方法:
// 作用域
String SCOPE_SINGLETON = "singleton"; // 单例作用域
String SCOPE_PROTOTYPE = "prototype"; // 原型作用域
// 设置父级 Bean 工厂
void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
// 设置 Bean 的类加载器,默认为线程上下文类加载器
void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);
// 获取 Bean 的类加载器
@Nullable
ClassLoader getBeanClassLoader();
// 设置临时的类加载器
void setTempClassLoader(@Nullable ClassLoader tempClassLoader);
// 获取临时的类加载器
@Nullable
ClassLoader getTempClassLoader();
// 设置是否缓存 Bean 的元数据
void setCacheBeanMetadata(boolean cacheBeanMetadata);
// 是否缓存 Bean 的元数据
boolean isCacheBeanMetadata();
// 设置 Bean 的表达式解析器,以统一的 EL 兼容样式支持 #{...} 这样的表达式
void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);
// 获取 Bean 的表达式解析器
@Nullable
BeanExpressionResolver getBeanExpressionResolver();
// 设置转换服务,用于转换属性值
void setConversionService(@Nullable ConversionService conversionService);
// 获取转换服务
@Nullable
ConversionService getConversionService();
// 添加属性编辑器注册者
void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);
// 为所有给定的属性注册自定义属性编辑器
void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);
// 使用在 BeanFactory 中注册的自定义编辑器来初始哈给定的属性编辑器注册者
void copyRegisteredEditorsTo(PropertyEditorRegistry registry);
// 设置类型转换器
void setTypeConverter(TypeConverter typeConverter);
// 获取类型转换器
TypeConverter getTypeConverter();
// 添加嵌入值解析器,例如注册属性
void addEmbeddedValueResolver(StringValueResolver valueResolver);
// 在BeanFactory是否有注册嵌入值解析器
boolean hasEmbeddedValueResolver();
// 解析给定的嵌入的值
@Nullable
String resolveEmbeddedValue(String value);
// 添加 Bean 的后置处理器
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
// 获取 Bean 的后置处理器个数
int getBeanPostProcessorCount();
// 注册作用域
void registerScope(String scopeName, Scope scope);
// 获取注册的作用域的名字
String[] getRegisteredScopeNames();
// 获取作用域
@Nullable
Scope getRegisteredScope(String scopeName);
// 提供一个与这个工厂有关的安全访问控制上下文
AccessControlContext getAccessControlContext();
// 从给定的其他的工厂拷贝所有相关的配置。不应该包含任何 Bean 的定义元数据
void copyConfigurationFrom(ConfigurableBeanFactory otherFactory);
// 注册别名
void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException;
// 解析所有别名的目标名称和在工厂中注册的别名,将给定的 StringValueResolver 应用于它们
void resolveAliases(StringValueResolver valueResolver);
// 获取合并的 Bean 的定义
BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 给定名字的 Bean是否为 FactoryBean
boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;
// 显式的设置指定 Bean 的目前在创建状态
void setCurrentlyInCreation(String beanName, boolean inCreation);
// 指定的 Bean 目前是否为在建状态
boolean isCurrentlyInCreation(String beanName);
// 注册给定 Bean 所依赖的 Bean
void registerDependentBean(String beanName, String dependentBeanName);
// 获取所有依赖于指定 Bean 的 Bean 的名字
String[] getDependentBeans(String beanName);
// 获取所有指定 Bean 所依赖的 Bean 的名字
String[] getDependenciesForBean(String beanName);
// 根据 Bean 的定义来摧毁给定的 Bean 的实例(通常是从工厂中获取到的原型实例)
void destroyBean(String beanName, Object beanInstance);
// 在当前目标作用域中摧毁指定的作用域中的 Bean
void destroyScopedBean(String beanName);
// 摧毁在工厂中的所有单例 Bean
void destroySingletons();
上面的大部分方法都是获取或者设置一些配置的信息,以便协同来完成 BeanFactory 的配置。
3.3 ConfigurableListableBeanFactory
ConfigurableListableBeanFactory
接口继承自 ListableBeanFactory
, AutowireCapableBeanFactory
, ConfigurableBeanFactory
。大多数具有列出能力的 Bean 工厂都应该实现此接口。此了这些接口的能力之外,该接口还提供了分析、修改 Bean 的定义和单例的预先实例化的机制。这个接口不应该用于一般的客户端代码中,应该仅仅提供给内部框架使用。
// 忽略用于自动装配的依赖的类型
void ignoreDependencyType(Class<?> type);
// 忽略用于自动装配的依赖的接口
void ignoreDependencyInterface(Class<?> ifc);
// 给特定的依赖类型注册自动装配的值
void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue);
// 指定的 Bean 是否为自动装配的候选者
boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException;
// 获取 Bean 的定义
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 获取这个工厂中的所有 Bean 的名字的迭代器
Iterator<String> getBeanNamesIterator();
// 清除元数据缓存
void clearMetadataCache();
// 冻结所有 Bean 的定义
void freezeConfiguration();
// 工厂中 Bean 的定义是否冻结了
boolean isConfigurationFrozen();
// 对非懒加载的单例进行预先初始化
void preInstantiateSingletons() throws BeansException;
3.4 AbstractBeanFactory
AbstractBeanFactory
继承自 FactoryBeanRegistrySupport
,实现了 ConfigurableBeanFactory
接口。AbstractBeanFactory
是 BeanFactory
的抽象基础类实现,提供了完整的 ConfigurableBeanFactory
的能力。在这里不讨论该抽象类的实现细节,只要知道这个类是干什么的就行了,会面会有更加详细的章节来讨论。
- 单例缓存
- 别名的管理
- FactoryBean 的处理
- 用于子 Bean 定义的 Bean 的合并
- Bean 的摧毁接口
- 自定义的摧毁方法
- BeanFactory 的继承管理
子类需要实现的模板方法如下:
// 是否包含给定名字的 Bean 的定义
protected abstract boolean containsBeanDefinition(String beanName);
// 根据 Bean 的名字来获取 Bean 的定义,子类通常要实现缓存
protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
// 为给定的已经合并了的 Bean 的定义创建 Bean 的实例
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException;
3.5 AbstractAutowireCapableBeanFactory
AbstractAutowireCapableBeanFactory
继承自 AbstractBeanFactory
,实现了 AutowireCapableBeanFactory
接口。该抽象了实现了默认的 Bean 的创建。
- 提供了 Bean 的创建、属性填充、装配和初始化
- 处理运行时 Bean 的引用,解析管理的集合、调用初始化方法等
- 支持构造器自动装配,根据类型来对属性进行装配,根据名字来对属性进行装配
子类需要自行实现的模板方法如下:
// 用于根据类型来进行自动装配
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;
3.6 DefaultListableBeanFactory
DefaultListableBeanFactory
继承自 AbstractAutowireCapableBeanFactory
,实现了 ConfigurableListableBeanFactory
, BeanDefinitionRegistry
, Serializable
接口。这个类是一个非常完全的 BeanFactory,基于 Bean 的定义元数据,通过后置处理器来提供可扩展性。
4. ApplicationContext 常见实现
4.1 ConfigurableApplicationContext
ConfigurableApplicationContext
是比较上层的一个接口,该接口也是比较重要的一个接口,几乎所有的应用上下文都实现了该接口。该接口在 ApplicationContext
的基础上提供了配置应用上下文的能力,此外提供了生命周期的控制能力。先看一下该接口的继承关系图:
Closeable
接口用于关闭应用上下文,释放所有的资源和锁,这也包括摧毁所有缓存的单例的 Bean,常见的 try-with-resources 用法如下,执行完 try 体中的代码后会自动的调用 close
方法:
try (ConfigurableApplicationContext cac = ...) {
// 编写代码
...
}
Lifecycle
定义了启动/停止生命周期的控制的一些方法,其中的方法如下:
void start(); // 启动组件
void stop(); // 停止组件
boolean isRunning(); // 组件是否正在运行
接下来看一下ConfigurableApplicationContext
中的方法:
void setId(String id); // 设置应用上下文唯一的 id
void setParent(ApplicationContext parent); // 设置应用程序上下文的父级
void setEnvironment(ConfigurableEnvironment environment); // 设置应用上下文的环境
ConfigurableEnvironment getEnvironment(); // 获取应用上下文的环境
// 添加一个新的 BeanFactoryPostProcessor
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
// 添加应用程序监听器
void addApplicationListener(ApplicationListener<?> listener);
// 添加协议解析器,可能会覆盖默认的规则
void addProtocolResolver(ProtocolResolver resolver);
// 加载或者刷新配置
void refresh() throws BeansException, IllegalStateException;
// 向 JVM runtime 注册一个关闭钩子,JVM 关闭时关闭这个上下文
void registerShutdownHook();
// 应用程序上问下是否是激活状态
boolean isActive();
// 获取应用上下文内部的 bean factory
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
上面的这些方法基本上是提供了对某些特性的实现进行支撑的方法。
看了这么多方法,下面看一下 ApplicationContext
的抽象的实现。
4.2 AbstractApplicationContext
AbstractApplicationContext
是 ApplicationContext
接口的抽象实现,这个抽象类仅仅是实现了公共的上下文特性。这个抽象类使用了模板方法设计模式,需要具体的实现类去实现这些抽象的方法。对相关接口的实现如下:
ApplicationContext
接口的实现ConfigurableApplicationContext
接口的实现BeanFactory
接口的实现ListableBeanFactory
接口的实现HierarchicalBeanFactory
接口的实现MessageSource
接口的实现ResourcePatternResolver
的实现Lifecycle
接口的实现
本文不会详细的讲解这个类中的具体的实现细节,后面会有更加的详细的介绍。下面看下里面的抽象方法:
// 刷新 BeanFactory,用于执行实际的配置加载,该方法在其他的初始化工作之前被 refresh() 方法调用
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
// 关闭 BeanFactory,用于释放内部使用的 BeanFactory·
protected abstract void closeBeanFactory();
// 获取内部使用的 BeanFactory
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
那么对需要实现的方法经过抽象后,只剩下少量的需要子类去实现的方法。
4.3 GenericApplicationContext
GenericApplicationContext
继承自 AbstractApplicationContext
,是为通用目的设计的,它能加载各种配置文件,例如 XML,properties 等等。它的内部持有一个 DefaultListableBeanFactory
的实例,实现了 BeanDefinitionRegistry
接口,以便允许向其应用任何 Bean 的定义的读取器。为了能够注册 Bean 的定义,refresh()
只允许调用一次。常见的使用如下:
GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
ctx.refresh();
MyBean myBean = (MyBean) ctx.getBean("myBean");
// ...
这个类的实现没有太多需要注意的地方,需要注意的有两点:
- 内部使用的
DefaultListableBeanFactory
的实例,提供了一些方法来配置该实例,例如是否允许 Bean 定义的覆盖、是否允许 Bean 之间的循环应用等等。 - 该类实现了
BeanDefinitionRegistry
,Bean 的定义注册。以便能通过BeanDefinitionReader
读取 Bean 的配置,并注册。BeanDefinitionRegistry
接口的实现是直接使用内部的DefaultListableBeanFactory
的实例。
4.4 AnnotationConfigApplicationContext
AnnotationConfigApplicationContext
继承自 GenericApplicationContext
,提供了注解配置(例如:Configuration、Component、inject等)和类路径扫描(scan 方法)的支持,可以使用 register(Class<?>... annotatedClasses)
来注册一个一个的进行注册。实现了 AnnotationConfigRegistry
接口,来完成对注册配置的支持,只有两个方法:register 和 scan。内部使用 AnnotatedBeanDefinitionReader
来完成注解配置的解析,使用 ClassPathBeanDefinitionScanner
来完成类路径下的 Bean 定义的扫描。