大道新途
应用开发中的容器,是指应用代码的运行框架。不基于容器的开发,是杂乱无章的,事实上,很多架构或者应用都是以容器为基础的,比如:EJB就是过去管理J2EE业务对象时最常用的容器。而J2EE的Web容器则比较特殊,它是用于管理servlet及其相关依赖对象的,Tomcat就是一个非常典型的Web容器。一般而言,容器都包含有比如生命周期管理、查找、配置管理以及依赖决策等基础服务,而且还会根据情况提供一些线程管理、对象池等增值服务。应用对象(大多数时候情况下,是业务逻辑)在容器里运行,也就是我们所谓的“被容器管理”。其实从Java刚刚问世不久,程序员们对容器在J2EE开发中的重要性已经有了比较清楚的认识,因为它可以极大地较低维护和管理的成本,也能进行接口和实体分离,以此降低耦合以及避免对Singleton的硬编程。合理的使用容器,可以很好的简化开发,然而,早期的重量级框架却都通过应用继承它们的类或实现它们的接口让应用与框架绑死。一个很典型的例子是EJB 2的无状态会话Bean。EJB 2并不是特例,其他流行框架也是如此,例如早期的Struts、WebWork 和 Tapestry,它们都存在强迫开发者编写大量冗余代码、应用与框架绑定等等缺陷。而轻量级容器就是为解决这些问题,而应运而生的。当然,我们称之为“轻量级容器”的架构,并没有完全脱离EJB架构的轨迹,它与EJB甚至有些相像:二者都是由容器管理业务对象,然后在围绕着这个服务层(对业务对象容器的改革是Spring关注的重点)组织整个架构。
尽管轻量级容器并不是Rod Johnson的首创,实际上它在2003年就已经泛滥,而控制轻量级容器的另一个核心依赖注入以及其核心要素依赖倒置原则,其实早已在EJB 2.5 和早期Tomcat身上就可以看到,在与Martin Fowler等人的早期技术讨论中,Rod Johnson明确了控制反转和依赖注入在未来编程中的重要性。并在随后发表的著作《Expert One-on-One J2EE Development without EJB》中,首次系统的阐述了轻量级容器,配合当时新兴的控制反转以减小代码对轻量级容器的依赖,同时对于当时单纯的控制反转在协作对象等等方面的不足提出了全新的解决办法,从而与Aop一起构建出全新的架构核心,并以此构建出全新的轻量级J2EE应用程序框架,在全新的Ioc容器中使用POJO业务对象并且由容器负责使用AOP提供声明式的企业级服务。希望借此来规避过去EJB种种的复杂性,去完成过去只有EJB才能做到的事,这便是Spring Ioc容器的设计初衷。
容器概述
IoC也被称作依赖注入(DI)。它是一个处理对象依赖项的过程,也就是将他们一起工作的其他的对象,只有通过构造参数、工厂方法参数或者(属性注入)通过构造参数实例化或通过工厂方法返回对象后再设置属性。当创建bean后,IoC容器再将这些依赖项注入进去。这个过程基本上是反转的,因此得名控制反转(IoC)。
下图是 IoC 的高级别视图
IoC容器利用Java的POJO类和配置元数据来生成 完全配置和可执行 的系统或应用程序。而Bean在Spring中就是POJO,也可以认为Bean就是对象。
设计实现
接口设计
Spring作为面向对象编程的集大成之作,我们直接从接口入手可以帮助我们更直观的了解Ioc容器的设计原理。
注1:笔者未能找到最新的Spring 4.0 接口体系图片,所以接口体系用都是Spring-3.1 接口体系,而分析的Sping 源码版本为:Spring-4.3。其实本来打算重新绘制新的接口体系,但分析过程中也发现两者鲜有差异,所以为了节省时间,固延用了老的版本。
注2:主要参考了《Spring技术内幕》第二版,但他的思维太过跳跃,所以我重新做了编排,还有就是很多细节部分参考了《Spring源码深度解析》,当然因为源码版本的不同,也会有些许差异。
下图描述了Ioc容器中的主要接口设计
这里主要是接口体系,而具体实现体系,比如DefaultListableBeanFactory就是为了实现ConfigurableBeanFactory,从而成为一个简单Ioc容器实现。与其他Ioc容器类似,XmlBeanFactory就是为了实现BeanFactory,但都是基于DefaultListableBeanFactory的基础做了扩展。同样的,ApplicationContext也一样。
从图中我们可以简要的做出以下分析:
1.从接口BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,这是一条主要的BeanFactory设计路径。在这条接口设计路径中,BeanFactory,是一条主要的BeanFactory设计路径。在这条接口设计路径中,BeanFactory接口定义了基本的Ioc容器的规范。在这个接口定义中,包括了getBean()这样的Ioc容器的基本方法(通过这个方法可以从容器中取得Bean)。而HierarchicalBeanFactory接口在继承了BeanFactory的基本接口后,增加了getParentBeanFactory()的接口功能,使BeanFactory具备了双亲Ioc容器的管理功能。在接下来的ConfigurableBeanFactory接口中,主要定义了一些对BeanFactory的配置功能,比如通过setParentBeanFactory()设置双亲Ioc容器,通过addBeanPostProcessor()配置Bean后置处理器,等等。通过这些接口设计的叠加,定义了BeanFactory就是最简单的Ioc容器的基本功能。
2.第二条接口设计主线是,以ApplicationContext作为核心的接口设计,这里涉及的主要接口设计有,从BeanFactory到ListableBeanFactory,再到ApplicationContext,再到我们常用的WebApplicationContext或者ConfigurableApplicationContext接口。我们常用的应用基本都是org.framework.context 包里的WebApplicationContext或者ConfigurableApplicationContext实现。在这个接口体现中,ListableBeanFactory和HierarchicalBeanFactory两个接口,连接BeanFactory接口定义和ApplicationContext应用的接口定义。在ListableBeanFactory接口中,细化了许多BeanFactory的接口功能,比如定义了getBeanDefinitionNames()接口方法;对于ApplicationContext接口,它通过继承MessageSource、ResourceLoader、ApplicationEventPublisher接口,在BeanFactory简单Ioc容器的基础上添加了许多对高级容器的特性支持。
3.这个接口系统是以BeanFactory和ApplicationContext为核心设计的,而BeanFactory是Ioc容器中最基本的接口,在ApplicationContext的设计中,一方面,可以看到它继承了BeanFactory接口体系中的ListableBeanFactory、AutowireCapableBeanFactory、HierarchicalBeanFactory等BeanFactory的接口,具备了BeanFactory Ioc容器的基本功能;另一方面,通过继承MessageSource、ResourceLoadr、ApplicationEventPublisher这些接口,BeanFactory为ApplicationContext赋予了更高级的Ioc容器特性。对于ApplicationContext而言,为了在Web环境中使用它,还设计了WebApplicationContext接口,而这个接口通过继承ThemeSource接口来扩充功能。
BeanFactory容器的设计
恩,我们与其写繁琐的文字,不如直接阅读代码来的直接的多。
最原始的容器:BeanFactory
package org.springframework.beans.factory;
import org.springframework.beans.BeansException;
import org.springframework.core.ResolvableType;
/**
* BeanFactory作为最原始同时也最重要的Ioc容器,它主要的功能是为依赖注入 (DI) 提供支持, BeanFactory 和相关的接口,比如,BeanFactoryAware、
* DisposableBean、InitializingBean,仍旧保留在 Spring 中,主要目的是向后兼容已经存在的和那些 Spring 整合在一起的第三方框架。在 Spring 中
* ,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一
* 个被配置化的系统或者应用。在资源宝贵的移动设备或者基于applet的应用当中, BeanFactory 会被优先选择。否则,一般使用的是 ApplicationContext
*
* 这里定义的只是一系列的接口方法,通过这一系列的BeanFactory接口,可以使用不同的Bean的检索方法很方便地从Ioc容器中得到需要的Bean,从而忽略具体
* 的Ioc容器的实现,从这个角度上看,这些检索方法代表的是最为基本的容器入口。
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 13 April 2001
*/
public interface BeanFactory {
/**
* 转定义符"&" 用来引用实例,或把它和工厂产生的Bean区分开,就是说,如果一个FactoryBean的名字为a,那么,&a会得到那个Factory
*
* FactoryBean和BeanFactory 是在Spring中使用最为频繁的类,它们在拼写上很相似。一个是Factory,也就是Ioc容器或对象工厂;一个
* 是Bean。在Spring中,所有的Bean都是由BeanFactory(也就是Ioc容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Be
* an,而是一个能产生或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似。
*/
String FACTORY_BEAN_PREFIX = "&";
/**
* 五个不同形式的getBean方法,获取实例
* @param name 检索所用的Bean名
* @return Object(<T> T) 实例对象
* @throws BeansException 如果Bean不能取得
*/
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
/**
* 让用户判断容器是否含有指定名字的Bean.
* @param name 搜索所用的Bean名
* @return boolean 是否包含其中
*/
boolean containsBean(String name);
/**
* 查询指定名字的Bean是否是Singleton类型的Bean.
* 对于Singleton属性,可以在BeanDefinition指定.
* @param name 搜索所用的Bean名
* @return boolean 是否包是Singleton
* @throws NoSuchBeanDefinitionException 没有找到Bean
*/
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
/**
* 查询指定名字的Bean是否是Prototype类型的。
* 与Singleton属性一样,可以在BeanDefinition指定.
* @param name 搜索所用的Bean名
* @return boolean 是否包是Prototype
* @throws NoSuchBeanDefinitionException 没有找到Bean
*/
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
/**
* 查询指定了名字的Bean的Class类型是否是特定的Class类型.
* @param name 搜索所用的Bean名
* @param typeToMatch 匹配类型
* @return boolean 是否是特定类型
* @throws NoSuchBeanDefinitionException 没有找到Bean
*/
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
/**
* 查询指定名字的Bean的Class类型.
* @param name 搜索所用的Bean名
* @return 指定的Bean或者null(没有找到合适的Bean)
* @throws NoSuchBeanDefinitionException 没有找到Bean
*/
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
/**
* 查询指定了名字的Bean的所有别名,这些都是在BeanDefinition中定义的
* @param name 搜索所用的Bean名
* @return 指定名字的Bean的所有别名 或者一个空的数组
*/
String[] getAliases(String name);
}
容器的基础:XmlBeanFactory
package org.springframework.beans.factory.xml;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.io.Resource;
/**
* XmlBeanFactory是BeanFactory的最简单实现类
*
* XmlBeanFactory的功能是建立在DefaultListableBeanFactory这个基本容器的基础上的,并在这个基本容器的基础上实行了其他诸如
* XML读取的附加功能。XmlBeanFactory使用了DefaultListableBeanFactory作为基础类,DefaultListableBeanFactory是一个很重
* 要的Ioc实现,会在下一章进行重点论述。
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Chris Beams
* @since 15 April 2001
*/
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* 根据给定来源,创建一个XmlBeanFactory
* @param resource Spring中对与外部资源的抽象,最常见的是对文件的抽象,特别是XML文件。而且Resource里面通常
* 是保存了Spring使用者的Bean定义,比如applicationContext.xml在被加载时,就会被抽象为Resource来处理。
* @throws BeansException 载入或者解析中发生错误
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* 根据给定来源和BeanFactory,创建一个XmlBeanFactory
* @param resource Spring中对与外部资源的抽象,最常见的是对文件的抽象,特别是XML文件。而且Resource里面通常
* 是保存了Spring使用者的Bean定义,比如applicationContext.xml在被加载时,就会被抽象为Resource来处理。
* @param parentBeanFactory 父类的BeanFactory
* @throws BeansException 载入或者解析中发生错误
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
最原始Ioc容器的使用
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
/**
* 最原始的Ioc容器使用,当然这也是Spring容器中效率最高的用法,比起繁琐的文字,阅读源码来得直观得多。
* 只需要写两行代码就行了,当然前提是要准备好Spring的配置文件
*
* @author kay
* @since 1.0
*/
@SuppressWarnings("deprecation")
public class SimpleBeanFactory {
public static void main(String[] args) {
ClassPathResource resource = new ClassPathResource("applicationContext.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Message message = beanFactory.getBean("message", Message.class); //Message是自己写的测试类
message.printMessage();
}
}
下面是XmlBeanFactory在使用过程中涉及到的类的关系图
图中空心三角加实线代表继承、空心三角加虚线代表实现、实线箭头加虚线代表依赖、实心菱形加实线代表组合。这里用下划线代表接口,没有下划线的代表类。
看着非常复杂是吧,不要紧,我们以代码来做简要说明
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
/**
* 这是与SimpleBeanFactory等效的编程式使用Ioc容器
*
* 从中我也可以看到一些Ioc的基本原理,同时也揭示了Ioc实现中的一些关键类:如Resource、DefaultListableBeanFactory
* 以及BeanDefinitionReader等等
*
* @author kay
* @since 1.0
*/
public class ProgramBeanFactory{
public static void main(String[] args) {
ClassPathResource resource = new ClassPathResource("applicationContext.xml");
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(resource);
Message message = factory.getBean("message", Message.class); //Message是自己写的测试类
message.printMessage();
}
}
以上,可以简单说明我们在使用Ioc容器时,需要如下几个步骤:
1,创建Ioc配置文件的抽象资源,这个抽象资源包含了BeanDefinition的定义信息。
2,创建一个BeanFactory,这里使用了DefaultListableBeanFactory。
3,创建一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML文件形式的BeanDefinition,通过一个回调配置给BeanFactory。
4,从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成。完成整个载入和注册Bean定义之后,需要的Ioc容器就建立起来了。这个时候我们就可以直接使用Ioc容器了。
恩,以下是Bean在使用过程中的解析、注册时效图,我们来一步一步分析,它是怎么在源码中实现的。
Bean的解析、注册详细过程分析
配置文件封装类:ClassPathResource
在Java中,将不同来源的资源抽象成URL,通过注册不同的handler(URLStreamHandler)来处理不同来源间的资源读取逻辑。而URL中却没有提供一些基本方法来实现自己的抽象结构。因而Spring对其内部资源,使用了自己的抽象结构:Resource接口来封装。而ClassPathResource实现类即是对Resource的实现。
Resource接口体系
资源的原始接口为Resource,它继承自InputStreamResource,实现了其getInstream方法,这样所有的资源就是通过该方法来获取输入流的。对于资源的加载,也实现了统一,定义了一个资源加载顶级接口ResourceLoader,它默认的加载就是DefaultResourceLoader。
InputStreamSource接口
package org.springframework.core.io;
import java.io.IOException;
import java.io.InputStream;
/**
* InputStreamSource 封装任何能返回InputStream的类,比如File、Classpath下的资源和Byte Array等
*
* @author Juergen Hoeller
* @since 20.01.2004
*/
public interface InputStreamSource {
/**
* 返回InputStream的类,比如File、Classpath下的资源和Byte Array等
* @return InputStream 返回一个新的InputStream的对象
* @throws IOException 如果资源不能打开则抛出异常
*/
InputStream getInputStream() throws IOException;
}
Resource接口
package org.springframework.core.io;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
/**
* Resource接口抽象了所有Spring内部使用到的底层资源:File、URL、Classpath等。
* 同时,对于来源不同的资源文件,Resource也有不同实现:文件(FileSystemResource)、Classpath资源(ClassPathResource)、
* URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等等。
*
* @author Juergen Hoeller
* @since 28.12.2003
*/
public interface Resource extends InputStreamSource {
/**
* 判断资源是否存在
* @return boolean 是否存在
*/
boolean exists();
/**
* 判断资源是否可读
* @return boolean 是否可读
*/
boolean isReadable();
/**
* 是否处于开启状态
* @return boolean 是否开启
*/
boolean isOpen();
/**
* 得到URL类型资源,用于资源转换
* @return URL 得到URL类型
* @throws IOException 如果资源不能打开则抛出异常
*/
URL getURL() throws IOException;
/**
* 得到URI类型资源,用于资源转换
* @return URI 得到URI类型
* @throws IOException 如果资源不能打开则抛出异常
*/
URI getURI() throws IOException;
/**
* 得到File类型资源,用于资源转换
* @return File 得到File类型
* @throws IOException 如果资源不能打开则抛出异常
*/
File getFile() throws IOException;
/**
* 获取资源长度
* @return long 资源长度
* @throws IOException 如果资源不能打开则抛出异常
*/
long contentLength() throws IOException;
/**
* 获取lastModified属性
* @return long 获取lastModified
* @throws IOException 如果资源不能打开则抛出异常
*/
long lastModified() throws IOException;
/**
* 创建一个相对的资源方法
* @param relativePath 相对路径
* @return Resource 返回一个新的资源
* @throws IOException 如果资源不能打开则抛出异常
*/
Resource createRelative(String relativePath) throws IOException;
/**
* 获取文件名称
* @return String 文件名称或者null
*/
String getFilename();
/**
* 得到错误处理信息,主要用于错误处理的信息打印
* @return String 错误资源信息
*/
String getDescription();
}
根据上面的推论,我们可以理解为这两段代码,在某种程度来说是完全等效的
ClassPathResource resource = new ClassPathResource("applicationContext.xml");
InputStream inputStream = resource.getInputStream();
Resource resource = new ClassPathResource("applicationContext.xml");
InputStream inputStream = resource.getInputStream();
这样得到InputStream以后,我们可以拿来用了。值得一提是,不同的实现有不同的调用方法,这里就不展开了。下面是ClassPathResource的具体实现:
ClassPathResource.java
private final String path;
private ClassLoader classLoader;
public ClassPathResource(String path) {
this(path, (ClassLoader) null); //这里是入口,直接跳入下面的ClassPathResource(String path, ClassLoader classLoader) 中
}
public ClassPathResource(String path, ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
忽略给定接口:DefaultListableBeanFactory
这里 DefaultListableBeanFactory 所起到的是忽略给定接口自动装配功能。简单来说,一般 bean 中的功能 A 如果没有初始化,那么Spring会自动初始化A,这是Spring的一个特性。但当某些特殊情况时,B不会初始化,比如:B已经实现了 BeanNameAware接口。可以说,就是通过其他方式来解析依赖,类似于 BeanFactory 的 BeanFactoryAware。下面是具体实现:
DefaultListableBeanFactory.java
public DefaultListableBeanFactory() {
super(); //直接指向下面 AbstractAutowireCapableBeanFactory()
}
AbstractAutowireCapableBeanFactory.java
private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<Class<?>>();
public AbstractAutowireCapableBeanFactory() {
super();
ignoreDependencyInterface(BeanNameAware.class); //忽略给定接口自动装配功能的主要实现处
ignoreDependencyInterface(BeanFactoryAware.class);
ignoreDependencyInterface(BeanClassLoaderAware.class);
}
public void ignoreDependencyInterface(Class<?> ifc) {
this.ignoredDependencyInterfaces.add(ifc);
}
BeanDefinition的载入、解析和注册:XmlBeanDefinitionReader
这里是BeanDefinition真正被载入的地方。这个载入过程就是把用户定义好的Bean表示成Ioc容器内部的数据结构,当然这个数据结构就是BeanDefinition。而BeanDefinition实际上就是POJO对象在Ioc容器中的抽象,通过这个BeanDefinition定义的数据结构,让Ioc容器能够对POJO对象也就是Bean进行管理。
XmlBeanDefinitionReader.java
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//loadBeanDefinitions的具体实现,而EncodedResource主要用于对资源文件的处理,而其主要实现方法getReader()在下面有所介绍
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
//通过属性来记录已经加载的资源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
// 调用DefaultResourceLoader的getResources方法完成具体的Resource定位
try {
//从EncodedResource中获取已经封装的Resource对象并再次从Resource中获取inputStream
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); //真正的逻辑核心
}
finally {
inputStream.close(); //关闭inputStream
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
/**
* 真正的核心处理部分
* 如果不考虑冗余的代码,其实只做三件事:
* 1.获取XML文件的验证模式
* 2.加载XML,并获取Document.
* 3.返回的Document,注册Bean
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 取得XML文件的Document对象, 这个解析过程由DefaultDocumentLoader完成
Document doc = doLoadDocument(inputSource, resource);
// 启动对BeanDefinition解析的详细过程, 解析过程中会使用到Spring的Bean配置规则
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
//loadDocument直接用于注册Document,getValidationModeForResource方法作用于XML的加载
return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
getValidationModeForResource(resource), isNamespaceAware());
}
EncodedResource.java
public Reader getReader() throws IOException {
if (this.charset != null) {
return new InputStreamReader(this.resource.getInputStream(), this.charset);
}
else if (this.encoding != null) {
return new InputStreamReader(this.resource.getInputStream(), this.encoding);
}
else {
return new InputStreamReader(this.resource.getInputStream());
}
}
XML文件验证
获取XML文件的验证模式,一般分为两步:首先,是XML文件验证,然后,就是验证模式的读取。
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> //XSD方式,用于验证XML文件的正确性
<bean id="..">...</bean>
</beans>
常用的XML文件验证方法有两种:DTD和XSD,DTD现在基本不用了,而上图中的spring-beans-4.0.xsd对应在源码中的org.springframework.beans.factory.xml.spring-beans-4.0.xsd。这里就不具体介绍了,有兴趣可以自己去研究。
加载XML
Spring中通过getValidationModeForResource方法来获取上面讲的DTD和XSD验证方法,不过就编程而言,还是非常简单的。只是要特别需要注意的是自动检测验证模式的实现。
XmlBeanDefinitionReader.java
public static final int VALIDATION_AUTO = XmlValidationModeDetector.VALIDATION_AUTO;
public static final int VALIDATION_XSD = XmlValidationModeDetector.VALIDATION_XSD;
protected int getValidationModeForResource(Resource resource) {
int validationModeToUse = getValidationMode();
//如果手动指定了验证模式则使用指定的验证模式
if (validationModeToUse != VALIDATION_AUTO) {
return validationModeToUse;
}
//如果没有指定,则自动检测
int detectedMode = detectValidationMode(resource); //自动检测主要是在detectValidationMode(Resource resource)完成的
if (detectedMode != VALIDATION_AUTO) {
return detectedMode;
}
return VALIDATION_XSD;
}
protected int detectValidationMode(Resource resource) {
if (resource.isOpen()) {
throw new BeanDefinitionStoreException(
"Passed-in Resource [" + resource + "] contains an open stream: " +
"cannot determine validation mode automatically. Either pass in a Resource " +
"that is able to create fresh streams, or explicitly specify the validationMode " +
"on your XmlBeanDefinitionReader instance.");
}
InputStream inputStream;
try {
inputStream = resource.getInputStream();
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Unable to determine validation mode for [" + resource + "]: cannot open InputStream. " +
"Did you attempt to load directly from a SAX InputSource without specifying the " +
"validationMode on your XmlBeanDefinitionReader instance?", ex);
}
try {
return this.validationModeDetector.detectValidationMode(inputStream); //自动检测则是给detectValidationMode完成的
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Unable to determine validation mode for [" +
resource + "]: an error occurred whilst reading from the InputStream.", ex);
}
}
XmlValidationModeDetector.java
public static final int VALIDATION_NONE = 0;
public static final int VALIDATION_AUTO = 1;
public static final int VALIDATION_DTD = 2;
public static final int VALIDATION_XSD = 3;
private static final String DOCTYPE = "DOCTYPE";
public int detectValidationMode(InputStream inputStream) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
try {
boolean isDtdValidated = false;
String content;
while ((content = reader.readLine()) != null) {
content = consumeCommentTokens(content);
//空或注释略过
if (this.inComment || !StringUtils.hasText(content)) {
continue;
}
if (hasDoctype(content)) {
isDtdValidated = true;
break;
}
//读取<前的信息
if (hasOpeningTag(content)) {
break;
}
}
return (isDtdValidated ? VALIDATION_DTD : VALIDATION_XSD);
}
catch (CharConversionException ex) {
return VALIDATION_AUTO;
}
finally {
reader.close();
}
}
private boolean hasDoctype(String content) {
return content.contains(DOCTYPE);
}
private boolean hasOpeningTag(String content) {
if (this.inComment) {
return false;
}
int openTagIndex = content.indexOf('<');
return (openTagIndex > -1 && (content.length() > openTagIndex + 1) &&
Character.isLetter(content.charAt(openTagIndex + 1)));
}
获取Document
通过以上的验证准备,就可以进行加载了,而XmlBeanDefinitionReader并没有自己去完成,而是给了DocumentLoader接口去完成的,而他调用的是DefaultDocumentLoader.loadDocument方法。loadDocument没有太多可描述的。所以。。。
XmlBeanDefinitionReader.java
private DocumentLoader documentLoader = new DefaultDocumentLoader();
//EntityResolver主要用于处理前面提到的DTD方法的处理
protected EntityResolver getEntityResolver() {
if (this.entityResolver == null) {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader != null) {
this.entityResolver = new ResourceEntityResolver(resourceLoader);
}
else {
this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
}
}
return this.entityResolver;
}
DefaultDocumentLoader.java
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);
return builder.parse(inputSource);
}
BeanDefinition的解析
BeanDefinition载入过程其实就是把定义的BeanDefinition在IoC容器中转化为一个Spring内部表示的数据结构的过程。IoC容器对Bean的管理和依赖注入的实现,都是通过对其持有的BeanDefinition进行各种相关的操作来完成的。这些BeanDefinition数据在IoC容器中通过一个HashMap来维护。
XmlBeanDefinitionReader.java
private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 得到BeanDefinitionDocumentReader来对XML的BeanDefinition进行解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 具体的解析过程在BeanDefinitionDocumentReader的registerBeanDefinitions方法中完成
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
DefaultBeanDefinitionDocumentReader.java
public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;
public static final String NESTED_BEANS_ELEMENT = "beans";
public static final String ALIAS_ELEMENT = "alias";
public static final String ALIAS_ATTRIBUTE = "alias";
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement(); // 获得Document的根元素
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
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)) {
return;
}
}
}
preProcessXml(root); // 解析Bean定义之前, 增强解析过程的可扩展性
parseBeanDefinitions(root, this.delegate); // 从Document的根元素开始进行Bean定义的Document对象
postProcessXml(root); // 解析Bean定义之前, 增强解析过程的可扩展性
this.delegate = parent;
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes(); // 获取Document对象根元素的所有子节点并循环解析
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
parseDefaultElement(ele, delegate); // 解析Spring的Bean规则默认元素节点
}
else {
delegate.parseCustomElement(ele); // 解析自定义元素节点
}
}
}
}
else {
delegate.parseCustomElement(root); // 解析自定义元素根节点
}
}
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { // 解析import元素
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { // 解析alias元素
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { // 解析bean元素
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // 解析内嵌beans元素, 作为根节点递归解析
doRegisterBeanDefinitions(ele);
}
}
恩,直接从代码就可以看出,Spring首先获取Document的根元素(一般为<beans/>),然后取得根元素所有的子节点并循环解析这些子节点;如果子节点在Spring默认的命名空间内,则按照Spring Bean定义规则来解析,否则按照自定义的节点解析。在按照Spring Bean定义规则进行解析的parseDefaultElement方法中,完成了对<import/>、<alias/>、<bean/>、<beans/>等元素的解析。
为了使文章简短一点,在这里只关注Spring对<bean>元素的解析过程,其它的解析过程不再分析。
DefaultBeanDefinitionDocumentReader.java
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 具体的解析委托给BeanDefinitionParserDelegate来完成
// BeanDefinitionHolder是BeanDefinition的封装类, 封装了BeanDefinition、Bean的名字和别名, 用它来完成向IoC容器注册.
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
BeanDefinitionParserDelegate.java
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
// 解析Bean定义资源文件中的<Bean>元素,主要处理<Bean>元素的id,name和aliase属性
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
// 如果<Bean>元素中没有配置id属性时, 将别名中的第一个值赋值给beanName
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
// 对<bean>元素进行详细解析
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
//为解析的Bean使用别名注册时, 为了向后兼容(Spring1.2/2.0给别名添加类名后缀)
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("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
this.parseState.push(new BeanEntry(beanName));
// 这里只读取<Bean>元素中配置的class名字, 然后载入到BeanDefinition中去
// 只是记录配置的class名字, 并不实例化, 对象的实例化在依赖注入时完成
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
// 根据<Bean>元素配置的class名称和parent属性值创建BeanDefinition, 为载入Bean定义信息做准备
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
// 对当前<Bean>元素中配置的一些属性进行解析, 如singleton、abstract等
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
// 对<Bean>元素的meta(元数据)、lookup-method、replaced-method等子元素进行解析
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
parseConstructorArgElements(ele, bd); // 解析<Bean>元素的构造方法参数
parsePropertyElements(ele, bd); // 解析<Bean>元素的<property>设置
parseQualifierElements(ele, bd);
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
return null;
}
<bean>元素解析已经完了,而<bean>元素属性及其子元素的解析顺序为:1,解析<bean>元素的属性。2,解析<description>子元素。3,解析<meta>子元素。4,解析<lookup-method/>子元素。5,解析<replaced-method>子元素。6,解析<constructor-arg>子元素。7,解析<property>子元素。8,解析<qualifier>子元素。解析过程中像<meta>、<qualifier>等子元素都很少使用,而下面就直接解析最常用的子元素<property>子元素。
BeanDefinitionParserDelegate.java
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
// 遍历<bean>所有的子元素
NodeList nl = beanEle.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
parsePropertyElement((Element) node, bd); // 如果是<property>元素, 则对其进行解析
}
}
}
public void parsePropertyElement(Element ele, BeanDefinition bd) {
String propertyName = ele.getAttribute(NAME_ATTRIBUTE); // <property>元素name属性
if (!StringUtils.hasLength(propertyName)) {
error("Tag 'property' must have a 'name' attribute", ele);
return;
}
this.parseState.push(new PropertyEntry(propertyName));
try {
// 如果同一个Bean中已经有相同名字的<property>存在, 直接返回
// 也就是说, 如果一个Bean中定义了两个名字一样的<property>元素, 只有第一个起作用.
if (bd.getPropertyValues().contains(propertyName)) {
error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
return;
}
// 解析<property>元素, 返回的对象对应<property>元素的解析结果, 最终封装到PropertyValue中, 并设置到BeanDefinitionHolder中
Object val = parsePropertyValue(ele, bd, propertyName);
PropertyValue pv = new PropertyValue(propertyName, val);
parseMetaElements(ele, pv);
pv.setSource(extractSource(ele));
bd.getPropertyValues().addPropertyValue(pv);
}
finally {
this.parseState.pop();
}
}
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
String elementName = (propertyName != null) ?
"<property> element for property '" + propertyName + "'" :
"<constructor-arg> element";
// 检查<property>的子元素, 只能是ref, value, list等(description, meta除外)其中的一个.
NodeList nl = ele.getChildNodes();
Element subElement = null;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
!nodeNameEquals(node, META_ELEMENT)) {
if (subElement != null) {
error(elementName + " must not contain more than one sub-element", ele);
}
else {
subElement = (Element) node;
}
}
}
// 判断property元素是否含有ref和value属性, 不允许既有ref又有value属性.
// 同时也不允许ref和value属性其中一个与子元素共存.
boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
if ((hasRefAttribute && hasValueAttribute) ||
((hasRefAttribute || hasValueAttribute) && subElement != null)) {
error(elementName +
" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
}
// 如果属性是ref属性, 创建一个ref的数据对象RuntimeBeanReference, 封装了ref信息
if (hasRefAttribute) {
String refName = ele.getAttribute(REF_ATTRIBUTE);
if (!StringUtils.hasText(refName)) {
error(elementName + " contains empty 'ref' attribute", ele);
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName);
ref.setSource(extractSource(ele));
return ref;
}
else if (hasValueAttribute) { // 如果属性是value属性, 创建一个数据对象TypedStringValue, 封装了value信息
TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
valueHolder.setSource(extractSource(ele));
return valueHolder;
}
else if (subElement != null) { // 如果当前<property>元素还有子元素
return parsePropertySubElement(subElement, bd);
}
else { // propery元素既没有ref或value属性, 也没有子元素, 解析出错返回null
error(elementName + " must specify a ref or value", ele);
return null;
}
}
恩,其实<property>元素还有子元素。
BeanDefinitionParserDelegate.java
public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
return parsePropertySubElement(ele, bd, null);
}
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
if (!isDefaultNamespace(ele)) { // 如果子元素没有使用Spring默认命名空间, 则使用用户自定义的规则解析
return parseNestedCustomElement(ele, bd);
}
else if (nodeNameEquals(ele, BEAN_ELEMENT)) { // 如果子元素是bean元素, 则使用解析<bean>元素的方法解析
BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
if (nestedBd != null) {
nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
}
return nestedBd;
}
else if (nodeNameEquals(ele, REF_ELEMENT)) { // 如果子元素是ref, 有且只能有bean、local和parent 3个属性中的一个
String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE); // 引用普通任意的bean
boolean toParent = false;
if (!StringUtils.hasLength(refName)) {
refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE); // 引用同一个XML配置文件中的bean
if (!StringUtils.hasLength(refName)) {
refName = ele.getAttribute(PARENT_REF_ATTRIBUTE); // 引用父容器中的bean
toParent = true;
if (!StringUtils.hasLength(refName)) {
error("'bean', 'local' or 'parent' is required for <ref> element", ele);
return null;
}
}
}
// ref元素没有bean、local和parent 3个属性中的一个, 返回null.
if (!StringUtils.hasText(refName)) {
error("<ref> element contains empty target attribute", ele);
return null;
}
RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
ref.setSource(extractSource(ele));
return ref;
}
else if (nodeNameEquals(ele, IDREF_ELEMENT)) { // 如果子元素是<idref>, 使用解析idref元素的方法解析
return parseIdRefElement(ele);
}
else if (nodeNameEquals(ele, VALUE_ELEMENT)) { // 子元素是<value>
return parseValueElement(ele, defaultValueType);
}
else if (nodeNameEquals(ele, NULL_ELEMENT)) { // 子元素是<null>
TypedStringValue nullHolder = new TypedStringValue(null);
nullHolder.setSource(extractSource(ele));
return nullHolder;
}
else if (nodeNameEquals(ele, ARRAY_ELEMENT)) { // 子元素是<array>
return parseArrayElement(ele, bd);
}
else if (nodeNameEquals(ele, LIST_ELEMENT)) { // 子元素是<list>
return parseListElement(ele, bd);
}
else if (nodeNameEquals(ele, SET_ELEMENT)) { // 子元素是<set>
return parseSetElement(ele, bd);
}
else if (nodeNameEquals(ele, MAP_ELEMENT)) { // 子元素是<map>
return parseMapElement(ele, bd);
}
else if (nodeNameEquals(ele, PROPS_ELEMENT)) { // 子元素是<props>
return parsePropsElement(ele);
}
else { // 以上都不是, 说明配置错误, 返回null.
error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
return null;
}
}
我们以<list>子元素进行分析
BeanDefinitionParserDelegate.java
public List<Object> parseListElement(Element collectionEle, BeanDefinition bd) {
// 获取<list>元素中的value-type属性, 即集合元素的数据类型
String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
NodeList nl = collectionEle.getChildNodes(); // <list>元素所有子节点
ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
target.setSource(extractSource(collectionEle));
target.setElementTypeName(defaultElementType);
target.setMergeEnabled(parseMergeAttribute(collectionEle));
parseCollectionElements(nl, target, bd, defaultElementType); // 具体解析List元素中的值
return target;
}
protected void parseCollectionElements(
NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {
// 遍历集合所有子节点
for (int i = 0; i < elementNodes.getLength(); i++) {
Node node = elementNodes.item(i);
if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
// 如果子节点是Element且不是<description>节点, 则添加进ManagedList.
// 同时触发对下层子元素的解析, 递归调用.
target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
}
}
}
不好意思,没子类了,BeanDefinition就被载入到IoC容器后,就可以在容器中建立了数据映射了。剩下的就是BeanDefinition注册了。
BeanDefinition的注册
BeanDefinition信息已经在IoC容器内部建立起了自己的数据结构,但这些数据还不能供IoC容器直接使用,需要在IoC容器中对这些BeanDefinition数据进行注册。不同的解析元素解析方式都不同但最后的注册的方式是一样的,我们还是以上面提到的<bean>元素为例。
BeanDefinitionReaderUtils.java
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
// 向IoC容器注册BeanDefinition
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 如果解析的BeanDefinition有别名, 向容器为其注册别名.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
上面的registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())是调用的注册位置,而BeanDefinitionRegistry仅仅是一个接口,而真正实现它的却是最原本的DefaultListableBeanFactory.registerBeanDefinition方法,值得一提的是DefaultListableBeanFactory.registerBeanDefinition方法在最新的Spring 4.0中稳定性方面做了很大改善。
DefaultListableBeanFactory.java
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
// 对解析得到的BeanDefinition校验
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
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注册过, 将Bean名字存入beanDefinitionNames
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
至此,注册完毕后,容器就可用了。虽然这是最原始的容器。
ApplicationContext容器的设计
恩,与上一章一样,直接上代码。
应用开发容器:ApplicationContext
package org.springframework.context;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.io.support.ResourcePatternResolver;
/**
* ApplicationContext是spring中较高级的容器。和BeanFactory类似,它可以加载配置文件中定义的bean,将所有的bean集中在一起,当有请求的
* 时候分配bean。 另外,它增加了企业所需要的功能,比如,从属性文件从解析文本信息和将事件传递给所指定的监听器。这个容器在org.springframework.
* context.ApplicationContext接口中定义。ApplicationContext包含BeanFactory所有的功能,一般情况下,相对于BeanFactory,ApplicationContext
* 会被推荐使用。但BeanFactory仍然可以在轻量级应用中使用,比如移动设备或者基于applet的应用程序。
*
* ApplicationContext接口关系
* 1.支持不同的信息源。扩展了MessageSource接口,这个接口为ApplicationContext提供了很多信息源的扩展功能,比如:国际化的实现为多语言版本的应用提供服务。
* 2.访问资源。这一特性主要体现在ResourcePatternResolver接口上,对Resource和ResourceLoader的支持,这样我们可以从不同地方得到Bean定义资源。
* 这种抽象使用户程序可以灵活地定义Bean定义信息,尤其是从不同的IO途径得到Bean定义信息。这在接口上看不出来,不过一般来说,具体ApplicationContext都是
* 继承了DefaultResourceLoader的子类。因为DefaultResourceLoader是AbstractApplicationContext的基类,关于Resource后面会有更详细的介绍。
* 3.支持应用事件。继承了接口ApplicationEventPublisher,为应用环境引入了事件机制,这些事件和Bean的生命周期的结合为Bean的管理提供了便利。
* 4.附件服务。EnvironmentCapable里的服务让基本的Ioc功能更加丰富。
* 5.ListableBeanFactory和HierarchicalBeanFactory是继承的主要容器。
*
* 最常被使用的ApplicationContext接口实现类:
* 1,FileSystemXmlApplicationContext:该容器从XML文件中加载已被定义的bean。在这里,你需要提供给构造器XML文件的完整路径。
* 2,ClassPathXmlApplicationContext:该容器从XML文件中加载已被定义的bean。在这里,你不需要提供XML文件的完整路径,只需正确配置CLASSPATH
* 环境变量即可,因为,容器会从CLASSPATH中搜索bean配置文件。
* 3,WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在XML文件中
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
/**
* 得到这个应用环境的独一无二ID
* @return 得到这个应用独一无二的ID,或者返回一个空值
*/
String getId();
/**
* 得到这个应用的名称
* @return 得到这个应用的名称,或者返回一个空值
*/
String getApplicationName();
/**
* 返回这个应用环境的显示名
* @return 这个应用环境的显示名,或者返回一个空值
*/
String getDisplayName();
/**
* 当这个应用第一次载入时,返回一个时间差(ms)
* @return 返回一个时间差(ms)
*/
long getStartupDate();
/**
* 得到一个父类的环境,或者空值
* @return 返回一个父类的环境,或者空值
*/
ApplicationContext getParent();
/**
* 你可以使用它来自动装配依赖对象,但这是一个非常专业的使用情况下,你在99.99%的时间是不需要他的。
* @return 这个应用环境的AutowireCapableBeanFactory接口
* @throws IllegalStateException 如果这个应用并不支持AutowireCapableBeanFactory接口,抛出异常
*/
AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;
}
ApplicationContext的层次结构
ApplicationContext的实现类种类太多,但它们的核心都是将对象工厂功能委托给BeanFactory的实现类DefaultListableBeanFactory,我们就以常用的实现类之一FileSystemXmlApplicationContext来解释。
ApplicationContext的实现方法:FileSystemXmlApplicationContext
package org.springframework.context.support;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
/**
* 在FileSystemXmlApplicationContext的设计中,我们看到ApplicationContext的主要功能其实已经在AbstractXmlApplicationContext
* 中完成了,而在FileSystemXmlApplicationContext只需要完成它自身的两个功能。
*
* 一个就是启动Ioc容器的refresh()过程。这个会在下一章进行重点论述。
* 另一个就是加载XML的Bean定义资源,主要是getResourceByPath方法来完成。
*
* @author Rod Johnson
* @author Juergen Hoeller
*/
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {
/**
* 创建FileSystemXmlApplicationContext类
*/
public FileSystemXmlApplicationContext() {
}
/**
* 根据父类,创建FileSystemXmlApplicationContext类
* @param parent 父类的接口
*/
public FileSystemXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
/**
* 根据XML文件名,创建FileSystemXmlApplicationContext类
* @param configLocation BeanDefinition所在的文件路径
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
/**
* 根据XML文件数组名,创建FileSystemXmlApplicationContext类
* @param configLocations XML文件名,可以指定多个BeanDefinition资源路径
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
this(configLocations, true, null);
}
/**
* 根据载入的父类接口,以及XML文件名自动刷新环境以及创建FileSystemXmlApplicationContext类
* @param configLocations XML文件名
* @param parent 父类接口,同时指定自己的双亲容器
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String[] configLocations, ApplicationContext parent) throws BeansException {
this(configLocations, true, parent);
}
/**
* 根据XML文件名自动刷新环境以及创建FileSystemXmlApplicationContext类
* @param configLocations XML文件名
* @param refresh 是否自动刷新环境
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh) throws BeansException {
this(configLocations, refresh, null);
}
/**
* 根据XML文件名、父类接口、自动刷新环境以及创建FileSystemXmlApplicationContext类
* 调用父类AbstractRefreshableConfigApplicationContext的方法,设置BeanDefinition定义的资源文件,完成IoC容器Bean定义资源的定位
* FileSystemXmlApplicationContext中最重要的实现方法,其他构建大部分都是基于它,类似的设计也在其他实现类中得以运用
*
* @param configLocations XML文件名
* @param refresh 是否自动刷新环境
* @param parent 父类接口,同时指定自己的双亲容器
* @throws BeansException 如果创建失败就抛出异常
*/
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh(); //Ioc容器的refresh()过程,是个非常复杂的过程,但不同的容器实现这里都是相似的,因此基类中就将他们封装好了
}
}
/**
* 加载XML Bean的给定资源
* 在文件应用中读取XML中的BeanDefinition以应对不同的BeanDefinition读取方式。
*
* @param string 具体路径
* @return Resource 返回一个具体资源
*/
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}
容器的入口:refresh
refresh定义在AbstractApplicationContext类中,它详细描述了整个ApplicationContext的初始化过程,比如BeanFactory的更新、MessageSource和PostProcessor的注册等。这里看起来像是对ApplicationContext进行初始化的模版或执行提纲,这个执行过程为Bean的生命周期管理提供了条件。
AbstractApplicationContext.java
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备刷新容器, 获取容器的当时时间, 同时给容器设置同步标识
prepareRefresh();
// 启动子类的refreshBeanFactory方法.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 为BeanFactory配置容器特性,例如类加载器、事件处理器等.
prepareBeanFactory(beanFactory);
try {
// 设置BeanFactory的后置处理.
postProcessBeanFactory(beanFactory);
// 调用BeanFactory的后处理器, 这些后处理器是在Bean定义中向容器注册的.
invokeBeanFactoryPostProcessors(beanFactory);
// 注册Bean的后处理器, 在Bean创建过程中调用.
registerBeanPostProcessors(beanFactory);
// 初始化上下文中的消息源.
initMessageSource();
// 初始化上下文中的事件机制.
initApplicationEventMulticaster();
// 初始化其它特殊的Bean.
onRefresh();
// 检查并向容器注册监听器Bean.
registerListeners();
// 实例化所有剩余的(non-lazy-init) 单例Bean.
finishBeanFactoryInitialization(beanFactory);
// 发布容器事件, 结束refresh过程.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例Bean, 以避免资源占用.
destroyBeans();
// 取消refresh操作, 重置 'active' 标志.
cancelRefresh(ex);
throw ex;
}
finally {
//重置Spring的核心缓存
resetCommonCaches();
}
}
}
ApplicationContext容器的使用
我们以ApplicationContext常用容器的使用来,说明容器的运作原理,实现类我们就用上面的FileSystemXmlApplicationContext,为什么用FileSystemXmlApplicationContext,其实我倒没什么立场问题,只是因为他简单也很具有代表性。而我们就将启动过程中,容器核心部分是如何启动进行说明。其他不作说明,因为太过庞杂了。
package com.kay.cn;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
/**
*
* @author kay
* @since 1.0
*/
public class Test {
public static void main(String[] arge) {
ApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
Message message = context.getBean("message", Message.class); //自己写的测试类
message.printMessage();
}
}
因为ApplicationContext和FileSystemXmlApplicationContext代码已经写了,下面是运行时的时效图,所以我们直接从AbstractXmlApplicationContext开始。
FileSystemXmlApplicationContext运行时效图
AbstractXmlApplicationContext.java
public AbstractXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
在AbstractXmlApplicationContext中其实,也已经完成仅仅只是继承一下。
AbstractRefreshableConfigApplicationContext.java
private String[] configLocations;
public AbstractRefreshableConfigApplicationContext(ApplicationContext parent) {
super(parent);
}
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;
}
}
而在AbstractRefreshableConfigApplicationContext中,除了继承父类方法,还有就是FileSystemXmlApplicationContext中setConfigLocations方法的实现,setConfigLocations方法主要用于载入XML。
AbstractRefreshableApplicationContext.java
private DefaultListableBeanFactory beanFactory;
public AbstractRefreshableApplicationContext(ApplicationContext parent) {
super(parent);
}
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory(); //容器开始初始化
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory); //容器的载入、解析和注册
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
在AbstractRefreshableApplicationContext类里,核心部分都在实现refreshBeanFactory方法中得到了实现。但是,却不是在这里进行的调用。
AbstractApplicationContext.java
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
最后在AbstractApplicationContext类中,进行了调用。通过同在AbstractApplicationContext中的refresh调用obtainFreshBeanFactory,进而调用子类中的refreshBeanFactory。至此,容器核心部分也就初始化完成。
依赖注入
上面对Ioc容器的初始化过程进行了分析,而这个初始化过程主要是在Ioc容器中建立BeanDefinition数据映射。但此过程并没有出现对Bean依赖关系进行注入,接下来我们对Bean依赖关系进行注入进行分析。
下面,我们对DefaultListableBeanFactory进行分析。但是对代码进行跟踪,却直接进入了DefaultListableBeanFactory的父类AbstractBeanFactory中。
这是依赖注入部分的时效图
AbstractBeanFactory.java
//--------------------------------------------------------------------------------------------
// 这里是对 BeanFactory 接口的实现,比如getBean接口方法
// 这些都是通过doGetBean来实现
// BeanFactory 接口 对应的5个实现,4个在这里,还有一个因为其特殊性并不是在这里重载或者实现的
//--------------------------------------------------------------------------------------------
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
//这个方法是我的程序调用的
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return doGetBean(name, requiredType, null, false);
}
public Object getBean(String name, Object... args) throws BeansException {
return doGetBean(name, null, args, false);
}
public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
return doGetBean(name, requiredType, args, false);
}
//这里是实际触发依赖注入的地方
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//指定名称获取被管理的Bean名称,并且指定名称中对容器的依赖
//如果是别名,将别名转变为Bean的名称
final String beanName = transformedBeanName(name);
Object bean;
//先缓存取得的Bean以及处理创建过的单件模式的Bean
//单态模式的Bean只能创建一次
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
//如果指定名称的Bean在容器中已经存在,则直接返回
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//这里完成FactoryBean的相关处理,对于FactoryBean,BeanFactory已经有所提及,在后面会详细分析
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//缓存中如果已经存在创建的单态模式,因为循环而创建失败,则抛出异常
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//对容器中的BeanDefinition进行检查,检查能否在当前的BeanFactory中取得Bean.
//如果在当前的工厂中取不到,则到父类的BeanFactory中去取
//如果在父类中取不到,则到父类的父类中取
BeanFactory parentBeanFactory = getParentBeanFactory();
//当前容器的父容器存在,且当前容器中不存在指名的Bean
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name); //解析Bean的原始名
if (args != null) {
//委派给父类容器查找,根据指定的名称和显示参数
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
///委派给父类容器查找,根据指定的名称和类型
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//创建的Bean是否需要进行验证,一般不需要
if (!typeCheckOnly) {
//向容器指定的Bean已被创建
markBeanAsCreated(beanName);
}
try {
//根据Bean的名字获取BeanDefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//获取当前Bean的所有依赖的名称
String[] dependsOn = mbd.getDependsOn();
如果当前Bean有依赖Bean
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
if (isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '"
+ dependsOnBean + "'");
}
//把被依赖的Bean注册给当前依赖的Bean
registerDependentBean(dependsOnBean, beanName);
//触发递归
getBean(dependsOnBean);
}
}
//创建单态模式的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) {
//清除显示容器单例模式Bean缓存中的实例对象
destroySingleton(beanName);
throw ex;
}
}
});
//获取给定Bean实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) { // 判断是否是原型模式
//原型模式会每次创建一个新的对象
Object prototypeInstance = null;
try {
//回调方法,注册原型对象
beforePrototypeCreation(beanName);
//创建指定Bean对象实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
//回调方法,Bean无法再次创建
afterPrototypeCreation(beanName);
}
//获取给定Bean的实例对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
//Bean定义资源中没有配置生命周期范围,则Bean不合法
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
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(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// 对创建的Bean进行类型检查,如果没有问题,就返回这个新建的Bean,这个Bean已经包含了依赖关系
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
从上面,可以看出doGetBean,是依赖注入的实际入口,他定义了Bean的定义模式,单例模式(Singleton)和原型模式(Prototype),而依赖注入触发的前提是BeanDefinition数据已经建立好的前提下。其实对于Ioc容器的使用,Spring提供了许多的参数配置,每一个参数配置实际上代表了一个Ioc实现特性,而这些特性的实现很多都需要在依赖注入的过程中或者对Bean进行生命周期管理的过程中完成。Spring Ioc容器作为一个产品,其真正的价值体现在一系列产品特征上,而这些特征都是以依赖反转模式作为核心,他们为控制反转提供了很多便利,从而实现了完整的Ioc容器。
下面是依赖注入的过程,下面我们重点进行分析。
bean实例的创建和初始化:createBean
getBean是依赖注入的起点,之后就会调用createBean,createBean可以生成需要的Bean以及对Bean进行初始化,但对createBean进行跟踪,发现他在AbstractBeanFactory中仅仅是声明,而具体实现是在AbstractAutowireCapableBeanFactory类里。
AbstractBeanFactory.java
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException;
AbstractAutowireCapableBeanFactory.java
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
//判断创建的Bean是否需要实例化,以及这个类是否需要通过类来装载
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
//校验和准备中的方法覆盖
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
//如果Bean配置了初始化前和后的处理器,则返回一个Bean对象
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;
}
//Bean的真正创建位置
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
// 这个BearWrapper是用来封装创建出来的Bean对象的
BeanWrapper instanceWrapper = null;
// 如果是单态模式,就先把缓存中同名的Bean清除
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
//创建Bean,由createBeanInstance来完成
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
//调用PostProcessor后置处理器
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
//缓存单态模式的Bean对象,以防循环引用
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);
}
});
}
//初始化Bean的地方,依赖注入发生的地方
//exposedObject在初始化完成后,会作为依赖注入完成后的Bean
Object exposedObject = bean;
try {
//将Bean实例对象进行封装,并将Bean定义的配置属性赋值给实例对象
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
//初始化Bean
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) {
//判断注册的实例化Bean和正在实例化的Bean是同一个
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
//当前Bean依赖其他Bean,并且当发生循环引用时不允许创建新实例
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
//获取当前Bean的所有依赖
for (String dependentBean : dependentBeans) {
//对依赖bean进行检查
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
//注册完成依赖注入的Bean
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
在对doCreateBean的追踪中我们发现Bean的创建方法createBeanInstance与BeanDefinition的载入与解析方法populateBean方法是最为重要的。因为控制反转原理的实现就是在这两个方法中实现的。
生成Bean中的对象:createBeanInstance
在createBeanInstance中生成了Bean所包含的Java对象,对象的生成有很多种不同的方法:工厂方法+反射,容器的autowire特性等等,这些生成方法都是由相关BeanDefinition来指定的。
AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 确认需要创建的Bean实例的类可以实例化
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//这里使用工厂方法对Bean进行实例化
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
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);
}
//使用默认构造函数对Bean进行实例化
return instantiateBean(beanName, mbd);
}
/**
* CGLIB是一个常用的字节码生成器的类库,他提供了一系列的API来提供生成和转换Java的字节码功能。
* 在Spring AOP中也使用CGLIB对Java的字节码进行了增强。
*/
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
protected InstantiationStrategy getInstantiationStrategy() {
return this.instantiationStrategy;
}
/**
* 最常见的实例化过程instantiateBean
* 使用默认的实例化策略对Bean进行实例化,默认的实例化策略是
* CglibSubclassingInstantiationStrategy,也就是用CGLIB来对Bean进行实例化
*/
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
//获取系统的安全管理接口
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
//实例化的对象封装
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
我们对CglibSubclassingInstantiationStrategy进行跟踪,发现Spring中的CGLIB生成,是由SimpleInstantiationStrategy.instantiate方法来完成的,所以我们就直接看SimpleInstantiationStrategy.instantiate。如果你对CGLIB有兴趣,可以仔细去研究,这里因为篇幅,所以。。。
SimpleInstantiationStrategy.java
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse; //指定构造器或者生成的对象工厂方法来对Bean进行实例化
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 (Exception ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
//通过BeanUtils进行实例化,这个BeanUtils的实例化通过Constructor来完成
return BeanUtils.instantiateClass(constructorToUse);
}
else {
//使用CGLIB来实例化对象
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
属性依赖注入实现:populateBean
Bean对象进行实例化以后。怎么把这些Bean对象之间的依赖关系处理好,以完成整个依赖注入,而这里就涉及到各种Bean对象依赖关系的处理过程了,而这些依赖关系都已经解析到了BeanDefinition。如果要仔细理解这个过程,我们必须从前面提到的populateBean方法入手。
AbstractAutowireCapableBeanFactory.java
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
//这里取得BeanDefinition中的property值
PropertyValues pvs = mbd.getPropertyValues();
//实例对象为NULL
if (bw == null) {
//属性不能为空
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
//实例对象为NULL,属性值也为空,不需设置,直接返回
return;
}
}
//在设置属性之前调用Bean的PostProcessor后置处理器
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
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的名字或者类型自动装配处理
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;
}
//检查日期是否持有用于单态模式Bean关闭时的后置处理器
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//Bean实例对象没有依赖,也没有继承
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处理器处理属性值
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
//对要配置的属性进行依赖检查
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
//对属性进行依赖注入
applyPropertyValues(beanName, mbd, bw, pvs);
}
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs == null || pvs.isEmpty()) {
return;
}
//封装属性值
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
if (System.getSecurityManager() != null) {
if (bw instanceof BeanWrapperImpl) {
//设置安全上下文,JDK安全机制
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
}
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
//属性值已经转换
if (mpvs.isConverted()) {
try {
//为实例化对象设置属性值
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
//获取属性值对象的原始类型值
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
//获取用户自定义的类型转换
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//创建一个Bean定义属性值解析器,将Bean定义中的属性值解析为Bean实例对象
//的实际值
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
//这里为解析值创建的一个副本,然后通过副本注入Bean
List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
//属性值不需要转换
if (pv.isConverted()) {
deepCopy.add(pv);
}
//属性值需要转换
else {
String propertyName = pv.getName();
//原始的属性值,即转换之前的属性值
Object originalValue = pv.getValue();
//转换属性值,例如将引用转换为IoC容器中实例化对象引用
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
//转换之后的属性值
Object convertedValue = resolvedValue;
//属性值是否可以转换
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
//使用用户自定义的类型转换器转换属性值
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
//存储转换后的属性值,避免每次属性注入时的转换工作
if (resolvedValue == originalValue) {
if (convertible) {
//设置属性转换之后的值
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
//属性是可转换的,且属性原始值是字符串类型,且属性的原始类型值不是
//动态生成的字符串,且属性的原始值不是集合或者数组类型
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
//重新封装属性的值
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted(); //标记属性值已经转换过
}
// 这里是依赖注入发生的地方
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
对代码的分析,我们知道当BeanDefinition完成载入和解析后,就进入依赖注入,这里以属性注入为例。但真正依赖注入的地方却是BeanWrapper接口。我们对BeanWrapper接口进行跟踪
他在doCreateBean中最先被定义,然后进入createBeanInstance
恩,最后,进入instantiateBean
最后得到BeanWrapperImpl,就是说依赖注入是在BeanWrapperImpl里完成的。但是以相同的方法对BeanWrapperImpl进行解析,最后发现AbstractNestablePropertyAccessor.setPropertyValue方法最为重要。
而对BeanWrapper接口的跟踪,我们发现,BeanWrapper是一个组件接口,根据源码分析,其作用是封装主程序中的Bean实例。以此,我们对applyPropertyValues重新分析,发现BeanDefinitionValueResolver.resolveValueIfNecessary方法是依赖注入的另一个关键下面,我们就对其进行分析。
属性值的解析:resolveValueIfNecessary
BeanDefinitionValueResolver.java
public Object resolveValueIfNecessary(Object argName, Object value) {
//对引用类型的属性进行解析
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
//调用引用类型属性的解析方法
return resolveReference(argName, ref);
}
//对属性值是引用容器中另一个Bean名称的解析
else if (value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference) value).getBeanName();
refName = String.valueOf(doEvaluate(refName));
//从容器中获取指定名称的Bean
if (!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException(
"Invalid bean name '" + refName + "' in bean reference for " + argName);
}
return refName;
}
//对Bean类型属性的解析,主要是Bean中的内部类
else if (value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}
else if (value instanceof BeanDefinition) {
BeanDefinition bd = (BeanDefinition) value;
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
}
//对集合数组类型的属性解析
else if (value instanceof ManagedArray) {
ManagedArray array = (ManagedArray) value;
Class<?> elementType = array.resolvedElementType; //获取数组的类型
if (elementType == null) {
String elementTypeName = array.getElementTypeName(); //获取数组元素的类型
if (StringUtils.hasText(elementTypeName)) {
try {
//使用反射机制创建指定类型的对象
elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
array.resolvedElementType = elementType;
}
catch (Throwable ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error resolving array type for " + argName, ex);
}
}
//没有获取到数组的类型,也没有获取到数组元素的类型,则直接设置数
//组的类型为Object
else {
elementType = Object.class;
}
}
//创建指定类型的数组
return resolveManagedArray(argName, (List<?>) value, elementType);
}
//解析list类型的属性值
else if (value instanceof ManagedList) {
return resolveManagedList(argName, (List<?>) value);
}
//解析set类型的属性值
else if (value instanceof ManagedSet) {
return resolveManagedSet(argName, (Set<?>) value);
}
//解析map类型的属性值
else if (value instanceof ManagedMap) {
return resolveManagedMap(argName, (Map<?, ?>) value);
}
//解析props类型的属性值,props其实就是key和value均为字符串的map
else if (value instanceof ManagedProperties) {
Properties original = (Properties) value;
Properties copy = new Properties(); //创建一个拷贝,用于作为解析后的返回值
for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
Object propKey = propEntry.getKey();
Object propValue = propEntry.getValue();
if (propKey instanceof TypedStringValue) {
propKey = evaluate((TypedStringValue) propKey);
}
if (propValue instanceof TypedStringValue) {
propValue = evaluate((TypedStringValue) propValue);
}
copy.put(propKey, propValue);
}
return copy;
}
//解析字符串类型的属性值
else if (value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue) value;
Object valueObject = evaluate(typedStringValue);
try {
Class<?> resolvedTargetType = resolveTargetType(typedStringValue); //获取属性的目标类型
if (resolvedTargetType != null) {
return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
}
//没有获取到属性的目标对象,则按Object类型返回
else {
return valueObject;
}
}
catch (Throwable ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error converting typed String value for " + argName, ex);
}
}
else {
return evaluate(value);
}
}
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
String refName = ref.getBeanName(); //获取引用的Bean名称
refName = String.valueOf(doEvaluate(refName));
//如果引用的对象在父类容器中,则从父类容器中获取指定的引用对象
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
return this.beanFactory.getParentBeanFactory().getBean(refName);
}
//从当前的容器中获取指定的引用Bean对象,如果指定的Bean没有被实例化
//则会递归触发引用Bean的初始化和依赖注入
else {
Object bean = this.beanFactory.getBean(refName);
//将当前实例化对象的依赖引用对象
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
}
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
属性值得依赖注入:setPropertyValue
AbstractNestablePropertyAccessor的setPropertyValue有三个,但都指向最后一个:
AbstractNestablePropertyAccessor.java
protected void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
//PropertyTokenHolder主要保存属性的名称、路径,以及集合的size等信息
String propertyName = tokens.canonicalName;
String actualName = tokens.actualName;
//keys是用来保存集合类型属性的size
if (tokens.keys != null) {
//将属性信息拷贝
PropertyTokenHolder getterTokens = new PropertyTokenHolder();
getterTokens.canonicalName = tokens.canonicalName;
getterTokens.actualName = tokens.actualName;
getterTokens.keys = new String[tokens.keys.length - 1];
System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);
Object propValue;
try {
//获取属性值,该方法内部使用JDK的内省(Introspector)机制,调用getter(readerMethod)方法,获取属性的值
propValue = getPropertyValue(getterTokens);
}
catch (NotReadablePropertyException ex) {
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
"Cannot access indexed value in property referenced " +
"in indexed property path '" + propertyName + "'", ex);
}
String key = tokens.keys[tokens.keys.length - 1]; //获取集合类型属性的长度
if (propValue == null) {
if (isAutoGrowNestedPaths()) {
int lastKeyIndex = tokens.canonicalName.lastIndexOf('[');
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
propValue = setDefaultValue(getterTokens);
}
else {
throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,
"Cannot access indexed value in property referenced " +
"in indexed property path '" + propertyName + "': returned null");
}
}
//注入array类型的属性值
if (propValue.getClass().isArray()) {
PropertyHandler ph = getLocalPropertyHandler(actualName); //获取属性的描述符
Class<?> requiredType = propValue.getClass().getComponentType(); //获取数组的类型
int arrayIndex = Integer.parseInt(key); //获取数组的长度
Object oldValue = null;
try {
//获取数组以前初始化的值
if (isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
oldValue = Array.get(propValue, arrayIndex);
}
//将属性的值赋值给数组中的元素
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, ph.nested(tokens.keys.length));
int length = Array.getLength(propValue);
if (arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
Class<?> componentType = propValue.getClass().getComponentType();
Object newArray = Array.newInstance(componentType, arrayIndex + 1);
System.arraycopy(propValue, 0, newArray, 0, length);
setPropertyValue(actualName, newArray);
propValue = getPropertyValue(actualName);
}
Array.set(propValue, arrayIndex, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Invalid array index in property path '" + propertyName + "'", ex);
}
}
//注入list类型的属性值
else if (propValue instanceof List) {
PropertyHandler ph = getPropertyHandler(actualName);
Class<?> requiredType = ph.getCollectionType(tokens.keys.length); //获取list集合的类型
List<Object> list = (List<Object>) propValue;
int index = Integer.parseInt(key); //获取list集合的size
Object oldValue = null;
if (isExtractOldValueForEditor() && index < list.size()) {
oldValue = list.get(index);
}
Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
requiredType, ph.nested(tokens.keys.length)); //获取list解析后的属性值
int size = list.size(); //为list属性赋值
//如果list的长度大于属性值的长度,则多余的元素赋值为null
if (index >= size && index < this.autoGrowCollectionLimit) {
for (int i = size; i < index; i++) {
try {
list.add(null);
}
catch (NullPointerException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Cannot set element with index " + index + " in List of size " +
size + ", accessed using property path '" + propertyName +
"': List does not support filling up gaps with null elements");
}
}
list.add(convertedValue);
}
else {
try {
list.set(index, convertedValue);
}
catch (IndexOutOfBoundsException ex) {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Invalid list index in property path '" + propertyName + "'", ex);
}
}
}
/注入map类型的属性值
else if (propValue instanceof Map) {
PropertyHandler ph = getLocalPropertyHandler(actualName);
Class<?> mapKeyType = ph.getMapKeyType(tokens.keys.length); //获取map集合key的类型
Class<?> mapValueType = ph.getMapValueType(tokens.keys.length); //获取map集合value的类型
Map<Object, Object> map = (Map<Object, Object>) propValue;
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(mapKeyType);
Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType, typeDescriptor); //解析map类型属性key值
Object oldValue = null;
if (isExtractOldValueForEditor()) {
oldValue = map.get(convertedMapKey);
}
//解析map类型属性value值
Object convertedMapValue = convertIfNecessary(propertyName, oldValue, pv.getValue(),
mapValueType, ph.nested(tokens.keys.length));
map.put(convertedMapKey, convertedMapValue); //将解析后的key和value值赋值给map集合属性
}
else {
throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,
"Property referenced in indexed property path '" + propertyName +
"' is neither an array nor a List nor a Map; returned value was [" + propValue + "]");
}
}
//对非集合类型的属性注入
else {
PropertyHandler ph = getLocalPropertyHandler(actualName);
if (ph == null || !ph.isWritable()) {
if (pv.isOptional()) {
if (logger.isDebugEnabled()) {
logger.debug("Ignoring optional value for property '" + actualName +
"' - property not found on bean class [" + getRootClass().getName() + "]");
}
return;
}
else {
throw createNotWritablePropertyException(propertyName);
}
}
Object oldValue = null;
try {
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
if (pv.isConverted()) {
valueToApply = pv.getConvertedValue();
}
else {
if (isExtractOldValueForEditor() && ph.isReadable()) {
try {
oldValue = ph.getValue();
}
catch (Exception ex) {
if (ex instanceof PrivilegedActionException) {
ex = ((PrivilegedActionException) ex).getException();
}
if (logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" +
this.nestedPath + propertyName + "'", ex);
}
}
}
valueToApply = convertForProperty(
propertyName, oldValue, originalValue, ph.toTypeDescriptor());
}
pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
}
ph.setValue(object, valueToApply);
}
catch (TypeMismatchException ex) {
throw ex;
}
catch (InvocationTargetException ex) {
PropertyChangeEvent propertyChangeEvent =
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
if (ex.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, ph.getPropertyType(), ex.getTargetException());
}
else {
Throwable cause = ex.getTargetException();
if (cause instanceof UndeclaredThrowableException) {
cause = cause.getCause();
}
throw new MethodInvocationException(propertyChangeEvent, cause);
}
}
catch (Exception ex) {
PropertyChangeEvent pce =
new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());
throw new MethodInvocationException(pce, ex);
}
}
}
好了,自此,依赖注入部分就完了。
其他特性
如果把Ioc容器比喻成一个人的话,Bean对象们就构成了他的骨架,依赖注入就是他的血肉,各种组件和支持则汇成了他的筋脉和皮肤,而各种特性则是他的灵魂。各种特性真正的使Spring Ioc有别于其他Ioc框架,也成就了应用开发的丰富多彩,Spring Ioc 作为一个产品,可以说,他的各种特性才是它真正的价值所在。
Spring Ioc的特性非常的多,了解了Spring Ioc容器整个运行原理后,按照相同思路分析这些特性相信也不是一件难事。如果读者感兴趣的话,也可以按照相同的思路进行研究。这里仅仅举个例子:
例子:Bean的完整生命周期
Spring Bean的完整生命周期从创建Spring容器开始,直到最终Spring容器销毁Bean,这其中包含了一系列关键点。
Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
1、Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法
2、Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
3、容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
4、工厂后处理器接口方法:这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
闲言小叙
Spring Ioc容器小结
Spring Ioc容器的核心是BeanFactory和BeanDefinition。分别对应对象工厂和依赖配置的概念。虽然我们通常使用的是ApplicationContext的实现类,但ApplicationContext只是封装和扩展了BeanFactory的功能。XML的配置形式只是Spring依赖注入的一种常用形式而已,而AnnotationConfigApplicationContext配合Annotation注解和泛型,早已经提供了更简易的配置方式,AnnotationConfigApplicationContext和AnnotationConfigWebApplicationContext则是实现无XML配置的核心接口,但无论你使用任何配置,最后都会映射到BeanDefinition。
其次,这里特别要注意的还是BeanDefinition, Bean在XML文件里面的展现形式是<bean id="...">...</bean>,当这个节点被加载到内存中,就被抽象为BeanDefinition了,在XML Bean节点中的那些关键字,在BeanDefinition中都有相对应的成员变量。如何把一个XML节点转换成BeanDefinition,这个工作自然是由BeanDefinitionReader来完成的。Spring通过定义BeanDefinition来管理基于Spring的应用中的各种对象以及它们之间的相互依赖关系。BeanDefinition抽象了我们对Bean的定义,是让容器起作用的主要数据类型。我们知道在计算机世界里,所有的功能都是建立在通过数据对现实进行抽象的基础上的。Ioc容器是用BeanDefinition来管理对象依赖关系的,对Ioc容器而言,BeanDefinition就是对控制反转模式中管理的对象依赖关系的数据抽象,也是容器实现控制反转的核心数据结构,有了他们容器才能发挥作用。
最后,其实IoC从原理上说是非常简单的,就是把xml文件解析出来,然后放到内存的map里,最后在内置容器里管理bean。但是看IoC的源码,却发现其非常庞大,看着非常吃力。这是因为spring加入了很多特性和为扩展性预留很多的接口,这些特性和扩展,造就了它无与伦比的功能以及未来无限的可能性,可以说正是他们将技术的美学以最简单的方法呈现在了人们面前,当然这也导致了他的复杂性。
太史公曰
Spring 的核心容器包括 Spring-Core、Spring-Context、Spring-beans、Spring-expression四个模块。不知你察觉没有, 笔者首先以BeanFactory容器为切入点,囊括了Bean的创建、解析以及定义和依赖注入的实现,都在Spring-beans的核心部分中。而Spring-Context和Spring-Core也一样,分别以ApplicationContext容器和Resource接口体系进行了囊括。Core模块主要就是定义了访问资源的方式,以及对于各种资源进行用统一的接口来抽象。而Context模块的主要作用则是为Bean对象提供、标识一个运行时环境,初始化BeanFactory并利用BeanFactory来将解析已经注册的Bean进而进行依赖注入,保存Bean对象之间的依赖关系。Context的主要职责是将Core和Bean两个模块融合在一起。而Spring-expression模块,笔者因为时间不够所以没有写,望大家见谅。
——水门(写于2016年02月)