标签:避免 one 接口设计 实例 高级 input 对象 实现类 potential
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
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
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容器的核心是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模块,笔者因为时间不够所以没有写,望大家见谅。
标签:避免 one 接口设计 实例 高级 input 对象 实现类 potential
原文地址:http://www.cnblogs.com/guoyongqiang/p/7267492.html