Spring IOC 实现原理
Spring IOC 实现原理
IOC: Inversion of Control ,即 "控制反转" , 不是什么技术,而是一种思想。原先需要自行实例化的对象, 交给IOC容器去实现。那么控制反转,谁被控制? 谁被反转 ?
在传统的JavaSE程序中,直接在类的内部通过new关键字来创建对象的实例,是程序主动去创建依赖对象,而IOC有一个专门的容器,来创建这些对象,由IOC容器来控制对象的创建,依赖对象也是容器帮忙查找创建并进行注入,对象只是被动的接受,依赖对象的获取被反转了。它还有一个更加形象的名字叫 依赖注入。
注入方式:
- 接口注入
- setter
- 构造器注入
IOC容器的设计与实现有两种:BeanFactory和ApplicationContext
IOC容器的两个容器设计系列:。
- 实现了BeanFactory接口的简单容器系列,只是实现了容器最基本的功能
- Applic ationContext应用上下文,作为容器的高级形态存在。除了具有基本的功能外,还增加了许多面向框架的特性,同时对应用环境做了许多适配。
BeanFactory
BeanFactory为IOC容器具体实现指定了基本的规范,换句话说BeanFactory是最顶层的类,它有三个子类,ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory接口。但是它们最终生成了一个默认的实现类DefaultListableBeanFactory。类的继承关系如下:
BeanFactory继承关系图.png
上图中DefaultListableBeanFactory的继承关系并不完整,删除了AliasRegistry接口的相关信息。
下面看一下BeanFactory接口中关于方法的定义:
public interface BeanFactory {
//通过使用转义符“&”,来区分BeanFactory产生的对象和BeanFactory本身
String FACTORY_BEAN_PREFIX = "&";
//根据Bean的名字获取Bean的实例
Object getBean(String var1) throws BeansException;
//根据Bean的名字和Class类型来获取实例,增加了类型安全验证
<T> T getBean(String var1, Class<T> var2) throws BeansException;
//根据Class类型来获取实例
<T> T getBean(Class<T> var1) throws BeansException;
//返回实例
Object getBean(String var1, Object... var2) throws BeansException;
//是否包含指定的实例
boolean containsBean(String var1);
//是否单例
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
//是否是原型
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
//类型是否匹配
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
//返回指定实例名的类型
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
//返回别名
String[] getAliases(String var1);
}
通过对上面方法的分析,可以得出。BeanFactory并不关心bean是如何定义,怎样被加载的,当我们需要bean的时候,直接来取就可以了。对于工厂来说,我只需要关心有没有产品,对于产品是怎么产生,怎么制作的,那是工人干的事,工厂并不关心。定义的都是最核心的接口,如getBean(),从容器中获取实例。
ApplicationContext
ApplicationContext是Spring提供的一个高级的IOC容器,除了提供基本IOC容器的功能外,还能为用户提供:
- 支持信息源,可以实现国际化
- 访问资源
- 支持应用事件
- ApplicationContext中提供的附加服务
看一下ApplicationContext的继承关系。
AppliciationContext继承关系图.png通过对上图的分析,可以看出ApplicationContext除了BeanFactory的功能,还具有ResourceLoader接口的功能,具有了高级容器特性的支持。
下面对接口的继承关系做一个简要的分析:
- 在BeanFactory中,从BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,是一个条主要的设计路径。 BeanFactory中定义了基本的IOC容器规范,在HierarchicalBeanFactory接口中增加了getparantBeanFactory()的接口功能,使BeanFactory具备了双亲IOC容器的管理功能,在ConfigurableBeanFactory主要定义了一些对BeanFactory的配置功能
- 在ApplicationContext中,从BeanFactory到ListableBeanFactory,再到ApplicationContext,再到常用的WebApplicationContext或者ConfigurableApplicationContext接口。在BeanFactory简单接口的基础上增加了对高级容器的特性支持。
BeanDefinition
SpringIOC容器帮我们管理了各种bean对象及其相互依赖的关系,Bean对象在Spring实现中是以BeanDefinition来描述的。*换句话说 依赖关系是使用BeanDefinition来保存的。 *其继承体系如下:
Spring关于Bean的装配,有下面三种方式:
- 在XML中进行显示配置
- 在java中进行显示配置
- 隐式的bean发现机制和自动装配
Bean的解析非常的复杂,功能被分的很细,需要扩展的地方也很多,必须保证有足够的灵活性,下面看一下基于xml配置文件解析的继承体系:
XmlBeanDefinitionReader的继承关系图.pngIOC容器的初始化
IOC容器的初始化包括:BeanDefinition的Resouce定位,BeanDefinition的载入和注册三个基本的过程。需要注意的是Spring把上面过程进行了分离,并使用了不同的模块来完成,定位使用了ResourceLoader,解析使用了BeanDefinitionReader等。这样设计的目的可以让用户对这三个过程进行裁剪和扩展,定义出适合自己的IOC容器初始化过程。
下面来看一下两种IOC容器的创建过程,BeanFactory以XmlBeanFactory为例,ApplicationContext 以 FileSystemXmlApplicationContext为例
XmlBeanFactroy
看一下XmlBeanFactory的源码定义:
public class XmlBeanFactory extends DefaultListableBeanFactory {
//定义一个BeanDefinitionReader阅读器
private final XmlBeanDefinitionReader reader;
//构造方法,需要传入Resource,资源的定位
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, (BeanFactory)null);
}
//构造方法重载,需要传入Resource,和父容器,此方法完成了读取器的初始化操作
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader = new XmlBeanDefinitionReader(this);
this.reader.loadBeanDefinitions(resource);
}
}
通过阅读XmlBeanFactory的源码可以看出。
XmlBeanFactory继承自DefaultListableBeanFactory类。而DefaultListableBeanFactory类包含了基本IOC容器所具有的重要功能。
那BeanDefinition的信息来源自哪,如何定位? 定位之后又如何读取解析呢??
对于信息来源的定位封装成Spring中的Resource类来给出,解析是它的内部定义了一个XmlBeanDefinitionReader对象,有了这个对象,就有了处理xml文件的能力。
参考XmlBeanFactory的实现,我们手动来模拟一下XmlBeanFactory的实现过程
//首先进行BeanDefinition资源文件的定位,封装为Source的子类
ClassPathResource res = new ClassPathResource("beans.xml");
//创建基本的IOC容器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//创建文件读取器,并进行回调设置。
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//资源加载解析
reader.loadBeanDefinitions(res);
通过上面的代码,总结一下IOC容器的使用步骤:
- 创建IOC抽象资源,这个抽象资源包含了BeanDefinition的定义信息
- 创建一个BeanFactory
- 创建一个BeanDefinition的读取器,通过一个回调配置给BeanFactory
- 从定义好的抽象资源中读取配置信息。完成载入和注册的定义后,IOC容器就建立了起来了。
FileSystemXmlApplicationContext
先来看一下FileSystemXmlApplicationContext的继承关系:
image.png通过上面的继承关系,可以发现它的基类AbstractXmlApplicationContext中已经实现了主要的功能。
在看一下这个类的源码实现,关于构造方法部分,我做了删减:
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
//构造方法重载,省略其他的构造方法
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if(refresh) {
this.refresh();
}
}
//通过一个FileSystemResource来得到一个在文件系统中定位的BeanDefinition
protected Resource getResourceByPath(String path) {
if(path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}
除了构造方法和getResourceByPath外,并没有其他的方法。也就说它只是实现了和它自身设计相关的两个功能。
看一下该类的调用方式:
ApplicationContext context =new FileSystemXmlApplicationContext(xmlPath);
上面调用了参数是字符串的构造函数,但是,对构造函数的调用最终都会转到下面的方法来执行,refresh方法启动了整个容器的初始化流程:
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if(refresh) {
this.refresh();
}
}
来看一下上面的构造方法中,最终都执行了那些操作,具体的操作都是由那些类执行的。
通过代码跟随,可以发现,super(parent)这个方法最终是由其基类(AbstractApplicationContext)来执行,执行了AbstractApplicationContext的无参构造方法和setParent()方法。其代码如下,省略了静态代码块的定义:
//FileSystemXmlApplicationContext调用父类构造方法就是该方法
public AbstractApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
//具体需要执行的方法
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
//获取一个Source的加载器用于读入Spring Bean 定义资源文件
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
//设置双亲ioc容器
public void setParent(ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
}
}
}
调用父类的构造方法执行完成后,返回FileSystemXmlApplicationContext类,执行setConfigLocations(configLocations)方法,该方法的定义在类AbstractRefreshableConfigApplicationContext中:
//处理资源定义的数组,解析Bean文件的定义路径
public void setConfigLocations(String[] locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
//解析路径
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
在资源定位的时候,支持下面两种方式:
- ClasspathResource res = new ClasspathResource("a.xml,b.xml");
- ClasspathResource res = new ClasspathResource("new String(){'a.xml' , 'b.xml'}")
具体实现的方式不在展开,感兴趣的可以去看一下源码实现
我们来看以上,程序执行到此处后,都做了哪些操作:
- 在AbstractApplicationContext中初始化了resourcePatternResolver(多资源文件的载入),用于获取Resource,关于何时使用后面再解释
- 将资源的定义路径保存在了configLocations数组中
到此,IOC容器根据资源定义路径获取Resouce的准备工作便完成了。
IOC容器的初始化过程
在开始分析初始化过程之前,先从宏观上对初始化的过程做一个简单的介绍,有一个大体框架的初始化模型,方便后面的理解,初始化过程分成了三个过程:
- Resource定位
- BeanDefinition的载入
- 向IOC容器注册这些BeanDefinition信息。这个过程是通过BeanDefinitionRegistry接口的实现来完成的。最终注入到HashMap中去,这个hashmap就是持有beandefinition数据的。
下面来看一下FileSystemXmlApplicationContext中的关于refresh()方法的调用,实际调用的是AbstractApplicationContext中的refresh()方法,该方法定义如下:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//环境准备,获取容器启动的时间,设置活动标志,以及属性的初始化
prepareRefresh();
//在子类中启动resreshBeanfactory()方法
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//为BeanFactory配置容器属性
prepareBeanFactory(beanFactory);
try {
//设置BeanFactory的后置处理
postProcessBeanFactory(beanFactory);
//调用后置处理,为这些后置处理器在Bean的定义中向容器注册
invokeBeanFactoryPostProcessors(beanFactory);
//注册Bean的后续处理,在Bean创建过程中调用
registerBeanPostProcessors(beanFactory);
//初始化上下文消息机制
initMessageSource();
//初始化上下文中事件机制
initApplicationEventMulticaster();
//初始化其他特殊的Bean
onRefresh();
//检查监听Bean并且将这些Bean向容器注册
registerListeners();
//初始化所有的singleton beans , 设置lazy-init = true 的bean除外
finishBeanFactoryInitialization(beanFactory);
//发布容器事件,结束Refresh过程
finishRefresh();
}catch (BeansException ex) {
// 为防止Bean资源占用,在异常处理中,销毁已经生成的单件Bean
destroyBeans();
//重置Rest标志
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
refresh()方法主要为IOC容器Bean的生命周期提供管理条件。Spring IOC容器的生成是从refreshBeanFactory()方法开始的,也就是执行了下面的代码:
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//使用委派模式,父类只是定义了方法,具体实现交给子类
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
在AbstractApplicationContext抽象类中,只是进行了refreshBeanFactory()方法的定义,方法的实现是在其子类AbstractRefreshableApplicationContext中实现的,在子类的定义如下:
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) { //如果已经有容器,则销毁并关闭容器
destroyBeans();
closeBeanFactory();
}
try {
//创建IOC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//对容器进行定制化,如设置启动参数,开启注解自动装配等
customizeBeanFactory(beanFactory);
//委派模式,资源的加载交给子类实现,启动对BeanDefinition的载入操作
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
上面代码loadBeanDefinitions(beanFactory);我们说是一个委派模式,只是进行了方法的定义,具体实现则是由AbstractXmlApplicationContext类实现,在该方法中创建了读取器XmlBeanDefinitionReader的实例,然后把这个读取器在IOC容器中设置好,最后是启动读取器来完成对BeanDefinition在IOC容器中的载入,定义如下:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建XmlBeanDefinitionReader
//即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器,读取Bean定义资源
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//为Bean读取器设置资源加载器
beanDefinitionReader.setResourceLoader(this);
//设置一个Sax实体用于解析
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//当Bean读取器读取Bean定义的xml资源文件时,启用xml校验机制
initBeanDefinitionReader(beanDefinitionReader);
//Bean 读取器真正的实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}
在XmlBeanDefinitionReader的初始化过程中,还进行了一些其他的操作,具体如下:
//调用父类的构造方法
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
//父类构造方法
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
//赋值
this.registry = registry;
//判断register是否是ResourceLoader 类型
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
//为resourceLoader 新建一个资源加载器
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
//判断register 是否是 EnvironmentCapable类型
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
//初始化一个environment
this.environment = new StandardEnvironment();
}
}
通过上面代码发现,在创建XmlBeanDefinitionReader的过程中,完成了resourceLoader和eviironment的赋值操作。
首先得到BeanDefinition信息的Resource定位,然后直接调用XmlBeanDefinitionReader来读取,具体的载入过程是委托给BeanDefinitionReader来完成的。因为使用的FileSystemXmlApplicationContext, getConfigResources()方法返回的是null,所以程序会走第二个分支
//Xml Bean读取器加载Bean定义资源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//获取资源定位
Resource[] configResources = getConfigResources();
if (configResources != null) {
//Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
reader.loadBeanDefinitions(configResources);
}
//如果子类获取的Bean定义为空,则获取FileSystemXmlApplication构造方法中setConfigLocations方法设置的资源。
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinition(configLocations);
}
}
程序分析到这,来梳理一下上面的执行流程。
-
在FileSystemXmlApplicationContext一共做了三件事
- 调用了父类的构造器,进行了初始化
- 设置了BeanDefinition的定义路径
- 执行了Refresh()方法
-
refresh()方法来启动整个BeanDefinition的载入过程
- 创建容器 DefaultListableBeanFactory
- 创建了XmlXmlBeanDefinitionReader
- 开始准备通过reader来加载资源
AbstractBeanDefinitionReader读取Bean定义资源,AbstractBeanDefinitionReader的loadBeanDefinitions方法源码如下:
//方法重载
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
String[] var3 = locations;
int var4 = locations.length;
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
counter += this.loadBeanDefinitions(location);
}
return counter;
}
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return this.loadBeanDefinitions(location, (Set)null);
}
//重载的最终执行方法
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//获取资源加载器
//上面提到过,XmlBeanDefinitionReader初始化时,在其父类中执行了加载器的初始化操作
//resourceLoader的类型为PathMatchingResourcePatternResolver
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//判断类型
if (resourceLoader instanceof ResourcePatternResolver) {
try {
//将指定位置的Bean定义资源文件解析转化为Resource
//加载多个指定位置的资源定义文件
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//读取Resource
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
Resource[] var3 = resources;
int var4 = resources.length;
for(int var5 = 0; var5 < var4; ++var5) {
Resource resource = var3[var5];
counter += this.loadBeanDefinitions((Resource)resource);
}
return counter;
}
上面的方法主要进行了两件事:
- 调用资源加载器获取资源 resourceLoader.getResource(location)
- 真正执行加载功能的是子类XmlBeanDefinitionReader的loadBeanDefinitions方法
loadBeanDefinitions()方法在AbstractBeanDefinitionReader中并没有具体的实现,它会转到XmlBeanDefinitionReader中的loadBeanDefinitions(Resource resource)中运行:
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//对xml资源进行编码处理
return this.loadBeanDefinitions(new EncodedResource(resource));
}
//方法重载,转入此方法执行
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if(this.logger.isInfoEnabled()) {
this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Object currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if(currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if(!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
//将资源文件转换为类型为InputStream的I/O流
InputStream ex = encodedResource.getResource().getInputStream();
try {
//从InputStream中得到xML的解析源
InputSource inputSource = new InputSource(ex);
//编码如果不为null, 则设置inputSource的编码
if(encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//读取数据
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
ex.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if(((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {
try {
//转化为Document 对象
Document doc = doLoadDocument(inputSource, resource);
//启动对Bean定义解析的详细过程,会用到Spring Bean的配置规则
return registerBeanDefinitions(doc, resource);
}
//删除了部分catch语句
catch (....) {
throw ex;
}
}
将XML文件转换成Document对象,解析过程由documentLoader实现,getValidationModeForResource(resource)验证xml文件的模式 DTD还是XSD,此方法不在展开。
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource,getEntityResolver(), this.errorHandler,getValidationModeForResource(resource),isNamespaceAware());
}
创建Document 的过程:
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
//创建文件解析工厂
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
//创建文档解析器
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
//解析Spring bean定义资源 ,并返回Document对象
return builder.parse(inputSource);
}
spring并没有对XML进行特殊的处理,使用了SAX对xml文档进行解析,操作分为三步:
- 创建DocumentBuilderFactory
- 创建DocumentBuilder
- 解析inputSource对象,返回Document 对象
Document对象代表了一个XML文档的模型树,所有的其他Node都以一定的顺序包含在Document对象之内,排列成一个树状结构,以后对XML文档的所有操作都与解析器无关,直接在这个对象上操作即可。NodeList代表了包含一个或者多个Node的列表,操作上可以看作数组,使用getLength()获得列表中的节点数,item(int index ) 返回集合中第index个项。Node对象很少使用,会使用它的自对象Element,Attr 等。
至此,Spring IOC容器根据定位的Bean定义资源文件,并将其加载读入转换为document对象的过程完成。
上面略微呢有一点跑题,document对象的创建过程可能不是我们最关心的,我们关心就是Spring的BeanDefinition是怎样按照Spring的Bean语义要求进行解析并转化为容器内部数据结构的。 这个过程是在下面的方法中执行的,我们来看一下,具体的操作过程:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建DocumentReader来对XML格式的BeanDefinition进行解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//获得容器中已经存在的Bean数量
int countBefore = getRegistry().getBeanDefinitionCount();
//具体的解析过程在这个方法中执行
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
Bean定义资源的解析分为以下两个过程:
- 通过调用xml解析器,将资源定义文件转换为Document对象,document对应并没有按照spring bean的规则进行解析。
- 在完成通用xml解析之后,按照Spring的Bean规则对Document对象进行解析,这个过程是在documentReader中实现的。具体的操作是由DefaultBeanDefinitionDocumentReader完成的。
处理的结果由BeanDefinitionHolder对象持有。解析过程由BeanDefinitionParserDelegate来实现。
来看下面的流程:
//根据Spring DTD 对bean定义的规则解析Bean定义Document对象
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
//获取xml描述符
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获得Document的根对象
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
//BeanDefinitionParserDelegate中定义了Spring Bean定义的XML文件的各种元素
//默认BeanDefinitionParserDelegate会处理”http://www.springframework.org/schema/beans“命名空间下元素及其属性
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
//对于默认的命名空间,首先开始的是对profile属性解析
//profile用得最多的是DataSource在不同环境下使用不同的bean
//spring使用StringTokenizer来进行字符串的分割,但是jdk为了兼容性是推荐使用String.split()方法的:
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//接下来的解析使用了模板模式
//进行自定义的解析,增强解析过程的可扩展性 ,空实现
preProcessXml(root);
//从Document的根元素开始进行Bean定义的document对象
parseBeanDefinitions(root, this.delegate);
//在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性。空实现
postProcessXml(root);
this.delegate = parent;
}
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate);
return delegate;
}
解析document文件,不同的命名的空间采用不同的方法处理
protected void parseBeanDefinitions(Element root,BeanDefinitionParserDelegate delegate) {
//Bean定义的Document对象使用了Spring默认的XML命名空间
if (delegate.isDefaultNamespace(root)) {
//获取Document对象的所有子节点,NodeList的含义上面进行了介绍
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i); //获取Node节点
//判断Node是否是Element类型
if (node instanceof Element) {
Element ele = (Element) node;
//判断该元素是否属于Spring定义Bean的默认命名空间
if (delegate.isDefaultNamespace(ele)) {
//使用Spring的Bean规则解析元素节点
parseDefaultElement(ele, delegate);
}
else {
//使用用户自定义的规则进行解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
//没有使用spring默认的命名空间,则使用用户自定义的解析规则解析
delegate.parseCustomElement(root);
}
}
使用spring的Bean规则解析Document元素节点,有些元素节点是<import> <bean> 等,则分别进行解析
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//如果元素节点是<Import>导入元素,进行导入解析
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//如果元素节点是<Alias>别名元素,进行别名解析
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//如果是<bean>转入此流程处理
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//如果是<beans>转入此流程处理
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
主要看一下对bean标签的解析过程。
protected void processBeanDefinition(Element ele,BeanDefinitionParserDelegate delegate) {
//BeanDefinitionHolder是对BeanDefinition的封装,delegate解析完成后使用holder封装,bdHolder 包含了id ,别名和BeanDefinition的信息
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//向容器注册封装后的实例
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
....
}
//在Beandefinition向IoC容器注册完成以后,发送消息
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
下面看一下parseBeanDefinitionElement()方法的具体实现,对于BeanDefinition的注册时存放在ConcurrentHashMap中的,beanName变为存放的健:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
//获取id的值
String id = ele.getAttribute(ID_ATTRIBUTE);
//获取name的值
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//分割name属性
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
//将id赋值给beanName
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("....");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//该方法引发对Bean元素的详细解析
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
//程序执行到此处,整个<bean>标签的解析就算结束了。一个beanDefinition就创建好了
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
//如果不存在beanName,那么根据Spring中的提供的命名规则为当前bean生成对应的beanName
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("....");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
//将信息封装到BeanDefinitionHolder中
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
BeanDefinition可以看成是对<bean>定义的抽象,这个数据对象中封装的数据大多都是与<bean>定义相关的,也有很多就是我们在定义Bean时看到的那些Spring标记。这个BeanDefinition数据类型是非常重要的,它封装了很多基本数据,这些都是Ioc容器需要的,上面代码最后我们返回了一个BeanDefinitionHolder实例,这个实例封装了beanDefinition,beanName, aliase三个信息,beanDefinition中也包含了beanName,aliase信息。
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
//这里只读取定义的<bean>中设置的class名字,然后载入到BeanDefinition中去,只是做个记录,并不涉及对象的实例化过程,对象的实例化过程实际是在依赖注入时完成的
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
//解析parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
//创建用于承载属性的AbstractBeanDefinition类型的GenereicBeanDefinition
//这里生成需要的BeanDefinition对象,为Bean定义的信息做载入做准备
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//这里对当前Bean元素进行属性解析,并设置description信息
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析元数据
parseMetaElements(ele, bd);
//解析lookup-method属性
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replaced-method属性
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析构造函数参数
parseConstructorArgElements(ele, bd);
//解析property子元素
parsePropertyElements(ele, bd);
//解析qualifier子元素
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
//返回BeanDefinition对象
return bd;
}
catch (ClassNotFoundException ex) {
...
}
catch (NoClassDefFoundError err) {
...
}
catch (Throwable ex) {
...
}
finally {
this.parseState.pop();
}
return null;
}
从上面的代码可以看出,要解析属性首先要创建用于承载属性的实例,也就是创建GenericBeanDefinition类型的实例,而代码createBeanDefinition(className,parent)的作用就是实现此功能。创建完承接的实例后,便可以进行各种属性的解析了,首先进行解析的是在<bean></bean>标签中定义的各种属性,如scope, singleton,abstract,lazy-init等,然后再解析子标签中的属性,如:lookup-method ,constructor-arg等。解析完成之后关联到实例上,之所以能进行关联,是因为xml中所有的配置都能在GenericBeanDefinition的实力类中找到对应的配置。 此时容器还没有起作用,要想起作用,需要向容器进行注册。
分析到这,已经完成了xml文件向BeanDefinition的转化,每个一个<bean>标签都会转化成一个BeanDefinition对应的实体。实体中包含了<bean>中定义的所有属性。
BeanDefinition在IOC容器中的注册
前面只是进行了BeanDefinition在IOC容器中的载入和解析过程,这些动作完成后,已经完成了定义的数据转化为BeanDefinition的过程。下面代码继续执行,看一下注册的过程,也就是processBeanDefinition函数中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry())的代码。
//registerBeanDefinition()方法的具体实现
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {
//获取beanName
String beanName = definitionHolder.getBeanName();
//使用beanName作为唯一标识注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//如果解析的BeanDefinition有别名,也要根据别名在注册一遍,不然根据别名找不到相应的信息
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
//beanName -> alias ,先将alias转换为beanName,在查找
registry.registerAlias(beanName, alias);
}
}
}
最终承接注册任务方法是在DefaultListableBeanFactory类中定义的,为了更好的排版,我对下面的代码进行了删减,主要删除了抛出异常信息和日志信息,并不影响代码的逻辑,对于beanDefinition的注册,做了一些验证之后,直接将beanDefinition放入了Map中:
//向IoC容器注册解析的BeanDefiniton
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
//注册前的最后一次校验
//主要是对AbstractBeanDefinition属性中的methodOverrides校验
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
....
}
}
BeanDefinition oldBeanDefinition;
//检查是否有同名的beanName存在,判断allowBeanDefinitionOveriding属性
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw ...
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("....");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("....");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("...");
}
}
//如果允许覆盖则执行覆盖操作
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//判断是否已经有其他的Bean开始初始化
//在容器启动的最后会预初始化所有的singleton beans
if (hasBeanCreationStarted()) {
//注册的过程中需要线程同步,以保证数据的一致性
synchronized (this.beanDefinitionMap) {
//注册
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
//正常情况下应该走此分支
//将BeanDefinition放入Map中,此map中保存了所有的BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
//这个ArrayList中会按照bean配置的顺序保存每一个注册的Bean的名字
this.beanDefinitionNames.add(beanName);
//手动注册singleton bean
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
至此,Bean定义资源文件中配置的Bean被解析过后,已经注册到IoC容器中,被容器管理起来,真正完成了IoC容器初始化所做的全部工作。现 在IoC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息是IoC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。
依赖注入
执行完上面的操作后,IOC容器已经实现了对Bean管理定义的相关数据,但是此时IOC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况下发生:
- 用户第一次通过getBean()方法想容器索取时,进行依赖注入
- 当用户在Bean的定义中为<bean>配置了lazy-init属性,让容器在解析注册时进行欲初始化,触发依赖注入
AbstactBeanFactory 通过getBean()函数获取被管理的Bean,但是因为lazyinit默认为false,所以spring会进行部分实例的初始化操作,让我们回退到AbstactApplicationContext类的finishBeanFactoryInitialization(beanFactory)方法,该方法进行了所有单例类的初始化操作,初始化的动作包装在了getBean()方法中,这个方法是获取Bean的地方,也是依赖注入发生的地方,对genBean的调用会转入到doGetBean()方法来执行,来看一下该方法的定义:
//根据执行的名称获取容器管理的Bean,已经初始化就直接返回,否则就先初始化在返回
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {
//提取定义的beanName,如果是别名,则将别名转换成规范的BeanName
final String beanName = transformedBeanName(name);
//定义Bean
Object bean;
//检查缓存中或者实例工厂中是否有对应的实例,单例模式的bean只创建一次
Object sharedInstance = getSingleton(beanName);
//如果实例已经创建,进入if分支 ,简单介绍一下参数args,一般情况下args为null,如果args不为null,则不是为了得到bean,而是为了创建bean
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("...");
}
else {
logger.debug("...");
}
}
//返回对应的实例,getObjectForBeanInstance完成的是FactoryBean的相关处理,已取得FactoryBean的生产结果,此处是FactoryBean和BeanFactory有区别。一个是创建工厂,一个是管理Bean工厂不一样。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//只有在单例情况下才会尝试解决循环依赖的问题,所谓循环依赖,是指:A中有B,B中有A , 形成了互相的引用
if (isPrototypeCurrentlyInCreation(beanName)) {
// 缓存中有指定名字的Bean但是由于循环引用创建失败了
throw new BeanCurrentlyInCreationException(beanName);
}
//检查一下这个BeanDefinition在容器中是否存在
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//如果当前容器不存在这个BeanDefinition,检查父容器中是否存在
String nameToLookup = originalBeanName(name);
if (args != null) {
//返回父容器的查询结果
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
//委派父级容器进行查找
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//不仅仅是做类型检查, 这里要进行记录
if (!typeCheckOnly) {
//向容器标记指定的Bean已经被创建
markBeanAsCreated(beanName);
}
try {
//执行到这,需要创建新的Bean了。无论是单例还是原型。根据名字获取Beandefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//先初始化所有的依赖bean
//注意这里的依赖是指定义在depends-on中的依赖
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
//检查一下循环依赖
if (isDependent(beanName, dep)) {
throw new BeanCreationException(。。。);
}
//注册依赖关系
registerDependentBean(dep, beanName);
//先初始化依赖项
getBean(dep);
}
}
//创建单例模式Bean实例
if (mbd.isSingleton()) {
//使用了匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
//创建bean,如果有父级继承,则合并子类和父类的定义
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//销毁单例beanName对象实例
destroySingleton(beanName);
throw ex;
}
}
});
//获取给定beanName的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//创建prototype的实例
else if (mbd.isPrototype()) {
//原型模式每次都会创建一个新的对象
Object prototypeInstance = null;
try {
//回调beforPrototypeCreateion方法,默认的功能是注册当前创建的原型对象
beforePrototypeCreation(beanName);
//创建实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
//回调afterPrototypeCreation方法,默认的功能告诉IOC容器指定bean的原型对象不在创建了
afterPrototypeCreation(beanName);
}
//获取给定的beanName实例对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//如果不是单例或者原型的话,则委托给响应的实现类来处理,例如request ,session , application等生命周期
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("...");
}
try {
//使用匿名内部类获取一个指定生命周期范围的实例
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
//获取给定Bean的实力对象
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(...);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
//最后检查一下类型对不对,不对的话就抛出异常,对的话就返回
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug(....);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
//将bean返回,此时的bean已经包含了依赖关系
return (T) bean;
}
OK,上面的流程走完了,接下来该分析分支方法了, 没错,就是那个方法crateBean(),其定义如下:
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
//确保BeanDefinition中的class被加载
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
//准备方法覆写,涉及到一个概念:MethodOverrides,来自于Bean定义的<lookup-method>和<replaced-method>。感兴趣的自行研究
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
//让BeanPostProcessors 有机会返回一个代理实例而不是bean实例
//要彻底了解清楚这个,需要看InstantiationAwwareBeanPostProcessor接口
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
//核心方法,创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
继续来看 doCreateBean()方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)throws BeanCreationException {
//这个BeanWrapper是用来持有创建出来的Bean对象的
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
//如果是singleton,先把缓存中的同名Bean清除
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建Bean的地方,由crateBeanInstance完成
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//这个就是Bean里面定义的类的实例
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null):
mbd.resolvedTargetType = beanType;
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//解决循环依赖问题
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//负责装配属性,给属性赋值
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
// 处理初始化后的各种回调
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(。。。);
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(。。。);
}
return exposedObject;
}
到此,doCreateBean方法便执行完了,上面的方法主要执行了三个步骤:
- 创建Bean实例createBeanInstance方法
- 依赖注入populateBean方法
- 回调方法initializeBean
下面介绍与依赖注入关系特别密切的方法createBeanInstance和populateBean方法。这个方法的主要作用就是实例化我们指定的类。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
//确保已经加载了此class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//校验这个类的访问权限
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(....);
}
if (mbd.getFactoryMethodName() != null) {
//采用工厂方法实例化
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
//使用构造函数实例化
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
//构造函数注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
//无参构造函数
return instantiateBean(beanName, mbd);
}
}
//判断是否采用有参构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//构造函数依赖注入
return autowireConstructor(beanName, mbd, ctors, args);
}
//调用无参构造函数
return instantiateBean(beanName, mbd);
}
在创建实例时,重要的是下面代码:
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
继续跟进一下:
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
判断一下是否存在方法覆写,如果不存在就使用java反射的方式创建实例,否则使用CGLIB来创建实例。
在这简单说一下,spring创建Bean的两种方式,一种是通过BeanUtis(JVM的反射功能,必须要基于接口才能实现),另一种就是CGLIB来生成。具体的不做深入分析,会放入AOP中来说明。到这实例的创建就完成了, 下面说一下属性的注入.
bean 属性注入,上面的代码已经完成了Bean对象的实例化,实例化对象已经生成,怎样把这些Bean对象的依赖关系处理好,依赖关系已经保存在了BeanDefinition中,看下面的方法:
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
//获取property的值。来自于BeanDefinition中。
PropertyValues pvs = mbd.getPropertyValues();
//判断实例是否为空
if (bw == null) {
//实例为空,属性不为空,抛出异常
if (!pvs.isEmpty()) {
throw new BeanCreationException(。。。);
}
else {
return;
}
}
// 到这步的时候,bean 实例化完成(通过工厂方法或构造方法),但是还没开始属性设值,
// InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改,
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 如果返回 false,代表不需要进行后续的属性设值,也不需要再经过其他的 BeanPostProcessor 的处理
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
//开始进行依赖注入过程,先处理autowire的注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 通过类型装配。复杂一些
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 这里有个非常有用的 BeanPostProcessor 进到这里: AutowiredAnnotationBeanPostProcessor
// 对采用 @Autowired、@Value 注解的依赖进行设值,这里的内容也是非常丰富的,不过本文不会展开说了,感兴趣的读者请自行研究
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// 设置 bean 实例的属性值
applyPropertyValues(beanName, mbd, bw, pvs);
}
initializeBean
属性注入完成后,这一步其实就是处理各种回调了。
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
// 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessBeforeInitialization 回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 处理 bean 中定义的 init-method,
// 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessAfterInitialization 回调
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
终于简单的分析完了,太不容易了。 spring的分支是在是太多了。很多地方都没有进行深究。以后有机会再慢慢看吧。
参考:
spring技术内幕
spring 源码分析
https://zhuanlan.zhihu.com/p/29344811
http://www.importnew.com/27469.html