组件扫描:自动发现应用容器中需要创建的Bean。 自动装配:自动满足Bean之间的依赖。
在第一个章节中,我们提到过,在Spring官方文档中,称org.springframework.context.ApplicationContext
这个接口就代表了Spring的容器,在解释ApplicationContext
之前,必须要先介绍Spring容器的基石,BeanFactory
接口。ApplicationContext
就是继承了BeanFactory
接口的一种高级容器接口。而BeanFactory
是简单容器的代表,是Spring容器家族的基石,所有的容器都必须实现这个接口。
首先,先看一下BeanFactory
接口的源码。
package org.springframework.beans.factory;
public interface BeanFactory {
/**
* 对FactoryBean的转移定义,提供获取FactoryBean实例的方法。
* 如果定义bean时是通过工厂模式配置Bean的,那么通过bean的名字检索FactoryBean时
* 得到的会是FactoryBean生产出来的实例,如果想得到工厂本身,需要进行转义
*/
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);
// 检索是否包含指定名字的bean
boolean containsBean(String name);
// 判断指定名字的bean是否为单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 判断指定名字的bean是否为原型
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
* 指定名字的Bean是否匹配指定的类型
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
/**
* 获取指定名字的Bean的类型
*/
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
// 获取指定名字Bean的所有别名
String[] getAliases(String name);
}
可以看出,BeanFactory
接口的源码并不复杂,主要规定了一些容器的基本功能,其中有7个获取Bean或者Bean提供者的方法,5个判断型的方法,2个获取类型的方法,1个获取别名的方法。通过这些方法,可以看出BeanFactory
是一个典型的工厂模式的工厂接口。
在之前的文章中我们提到过:Spring框架的设计中,充满了通过上下继承关系来对基类进行功能扩充与功能分隔的类体系。 BeanFactory
体系也是如此。
下面看一下在顶级容器接口的下面,Spring又做了哪些骚操作吧:
BeanFactory家族的核心成员主要就是上面的几个,其关系类图如图所示,BeanFactory位于家族顶层。这些接口和实现类,每一个都代表了对BeanFactory不同方向的功能扩展,下面逐一进行分析。
ListableBeanFactory
和HierarchicalBeanFactroy
。ListableBeanFactory
:该接口拥有列出工厂中所有Bean的能力。public interface ListableBeanFactory extends BeanFactory {
// 检索是否包含给定beanName的BeanDefinition
boolean containsBeanDefinition(String beanName);
// 获取工厂中BeanDefinition的数量
int getBeanDefinitionCount();
// 获取工厂中所有BeanDefinition的Names
String[] getBeanDefinitionNames();
// 获取指定类型的beanNames
String[] getBeanNamesForType(ResolvableType type);
String[] getBeanNamesForType(ResolvableType type, boolean includeNonSingletons, boolean allowEagerInit);
String[] getBeanNamesForType(@Nullable Class<?> type);
String[] getBeanNamesForType(@Nullable Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
// 根据指定的类型来获取所有Bean
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException;
// 根据指定的直接获取beanNames
String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType);
// 获取所有指定注解标注的Bean实例,Autowired就是使用的该接口
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
// 查找指定Bean中含有的注解类型
@Nullable
<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType)
throws NoSuchBeanDefinitionException;
}
可以看出ListableBeanFactory主要对外提供了批量
获取Bean和BeanDefinition的方法,拓展类了BeanFactory的功能,是一个非常重要的接口。
HierarchicalBeanFactroy
接口:顾名思义,这是一个分层的工厂。该接口实现了Bean工厂的分层。public interface HierarchicalBeanFactory extends BeanFactory {
/**
* 返回父级工厂
*/
@Nullable
BeanFactory getParentBeanFactory();
/**
* 检索本地工厂是否包含指定名字的Bean
*/
boolean containsLocalBean(String name);
}
这个接口非常简单,也是继承自BeanFactory,虽然简单,但却提供了一个非常重要的功能——工厂分层。工厂分层有什么用呢?通过工厂分层,SpringIoC容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的Bean,而父容器不能访问子容器中的Bean。在容器内,Bean的id必须是唯一的,但子容器可以拥有一个和父容器id相同的Bean。
父子容器层级体系增强了Spring容器架构的扩展性和灵活性,因为第三方可以通过编程的方式,为一个已经存在的容器添加一个或多个特殊用途的子容器,以提供一些额外的功能。
Spring使用父子容器实现了很多功能,比如在Spring MVC中,展现层Bean位于一个子容器中,而业务层和持久层的Bean位于父容器中。这样,展现层Bean就可以引用业务层和持久层的Bean,而业务层和持久层的Bean则看不到展现层的Bean。
ConfigurableBeanFactory
接口ConfigurableBeanFactory接口是一个继承了HierarchicalBeanFactroy
的子接口,同时该接口还继承了SingletonBeanRegistry
接口,SingletonBeanRegistry
是一个用来注册单例类的接口,提供了同意访问单例Bean的功能,该接口的方法如下图:
也就是说ConfigurableBeanFactory
同时拥有了工厂分层和单例注册的功能,并且为了不辜负ConfigurableBeanFactory这个名字,该接口又继续扩展了几十个方法!加上继承来的方法,这个接口中的方法数量非常之多。
该接口主要扩展了一些复杂的对单例Bean的配置与操作,虽然这个接口并没有被ApplicationContext高级容器体系所继承,但是一般的容器实现类都会继承或实现这个接口,目的是使用一种统一的方式对外暴露管理单例Bean的方式。
AutowireCapableBeanFactory
接口该接口直接继承自BeanFactory接口,扩展出了工厂的自动装配功能,其提供的方法如下:
该接口主要作用是将自动装配的能力对外暴露出来,可以通过实现此接口实现自动装配能力,但是正常情况下不应该使用该接口。此接口主要针对框架之外,没有向Spring托管的Bean的应用。其中比较重要的知识是四种自动装配策略:
// 用于表示外部自动装配功能是否可用,但是不影响自动装配功能的使用
int AUTOWIRE_NO = 0;
// 标识 按名称自动装配
int AUTOWIRE_BY_NAME = 1;
// 标识 按类型自动装配 Autowired默认使用的该装配策略
int AUTOWIRE_BY_TYPE = 2;
// 标识 按照贪婪策略匹配到的最合适构造器来自动装配
int AUTOWIRE_CONSTRUCTOR = 3;
ConfigurableListableBeanFactory
接口此工厂接口看类名即可知道,是一个继承了ListableBeanFactory
和ConfigurableBeanFactory
接口的子接口,同时它还继承了AutowireCapableBeanFactory
接口,并且自身还扩展了一些功能,加在一起,这个接口的方法大概有接近100之巨。该接口总体上是继承多种父接口,并对功能进行略微扩展补充,包含了BeanFactory接口体系目前的所有方法,是Bean工厂接口的集大成者。
AbstractBeanFactory
抽象类AbstractBeanFactory
这个抽象类是Spring容器体系中最重要的一个抽象类,该抽象类实现了BeanFactory重要的二级接口ConfigurableBeanFactory
,实现了其中的绝大多数基本方法,实现了Bean工厂的许多重要功能,如对BeanDefinition、原型、单例Bean的各种操作。
由于该抽象类实现方法繁多,逻辑复杂,若是详细分析贴出代码就容易陷入细节不能自拔,与本系列文章目的相悖,这里就不具体深入分析源码了,网上关于源码的详细分析也比较多,读者若是感兴趣,可以自行阅读与学习。
这里需要多拓展一步,更加深入对AbstractBeanFactory
的了解,从源码中我们可以发现,AbstractBeanFactory
其实还继承了另外一个抽象类——FactoryBeanRegistrySupport
:
如果我们将AbstractBeanFactory
的继承关系类图打开,会发现还有另外一个体系分支:
这个继承体系是Spring的AliasRegistry体系,也就是别名注册接口体系,具体的分析见:AliasRegistry接口体系。
AbstractBeanFactory
既然继承了这个体系,说明容器本身也是个别名注册器、FactroyBean注册器和单例Bean注册器,也会维护别名注册表、支持FactroyBean的注册和单例Bean注册的各种操作(注册、获取、移除、销毁等)。
DefaultListableBeanFactory
类DefaultListableBeanFactory
类是Spring提供的默认简单容器实现类,也是从BeanFactory接口一路继承与实现下来的第一个可以独立运行的容器类,该类间接继承了AbstractBeanFactory
抽象类,同时还实现了Spring集大成的容器接口——ConfigurableListableBeanFactory
接口,这保证了DefaultListableBeanFactory
完整实现了简单容器中对Bean的各种操作功能。
而且我们还在源码中发现,DefaultListableBeanFactory
同时还实现了BeanDefinitionRegistry
接口,关于这个接口的具体介绍见:向容器中注册BeanDefinition——BeanDefinitionRegistry。正是因为实现了此接口,所以DefaultListableBeanFactory
也是一个BeanDefinition注册器,拥有了注册BeanDefinition的作用。可以从源码中发现,DefaultListableBeanFactory
中维护了一个beanDefinitionMap
,即BeanDefinition注册表。
以上,BeanFactory简单容器体系就介绍完了,下面进入高级容器——ApplicationContext部分。
ApplicationContext
直接翻译也被称作应用上下文
,其实这个字面很难被理解,Context
的意思是上下文
、环境
,其实个人认为翻译成应用环境
可能会更好一些,可以认为ApplicationContext
是一种定义了维护BeanDefinition
和实例化对象
之间协作关系
的高级接口,而这个高级接口,又是利用了Spring中普通容器来实现的,所以也被称作高级容器,也是我们平时认为的Spring容器体系,因为BeanFactroy
虽然也是容器,但是平时我们直接接触不到,作为用户,平时在使用的时候,我们直接用的是ApplicationContext
高级容器,也就是说,高级容器是面向用户的,而普通容器是面向框架的,是Spring容器的基石。
ApplicationContext
接口继承自BeanFactory
的二级接口ListableBeanFactory
和HierarchicalBeanFactroy
。所以高级容器其实也是在普通容器的基础上实现的,在普通容器的基础上扩展除了非常丰富的功能接口来供用户使用,如果深入去阅读源码,会发现其实在高级容器的一个很重要的抽象类AbstractRefreshableApplicationContext
内部,是有一个私有的普通容器对象的,而我们常用的一些高级容器实现类,比如FileSystemXmlApplicationContext
、AnnotatioConfigWebApplicationContext
等都继承自这个抽象类,也就是说都继承了这个普通容器对象:
这个内部的DefaultListableBeanFactory
对象,通常也被称作内部容器,Spring的设计大量运用了委托模式的思想,这里在高级容器内部实例化一个内部容器出来,将普通容器的所有操作都委托给内部容器去实现,而高级容器本身只需要关注与拓展面向用户的操作即可。
下图是ApplicationContext
体系类图,之后我们将展开分析一下这个体系:
ApplicationContext
接口首先,ApplicationContext
接口继承自ListableBeanFactory
和HierarchicalBeanFactroy
,也就是ApplicationContext
下面的接口和类,都继承或者实现了BeanFactroy体系中的大部分功能,包括对BeanDefinition的单个与批量操作和容器分层的方法。在此基础上,ApplicationContext
还同时继承了其它四个接口,对容器进行了方法的扩展,其源码如下: