总述:spring框架是如今J2EE开发最重要框架之一,为企业级应用提供一系列轻量级解决方案,比如:基于依赖注入的核心机制、基于AOP的声明式事务管理、与多种持久层技术整合、整合后端各种组件等等。贯穿了表现层、业务层、持久层,实现无缝整合。
文章结构:(1) 框架总述;(2)以Bean为核心的IOC/DI机制;
一、框架总述:
图选自疯狂Java讲义。文字参考:此博主此文章。本博主在此摘抄并补充下
(1)Core Container(核心容器):
包含有Core,Beans,Context,Expression Language模块。是框架的基础部分,提供IOC(控制反转)和依赖注入特性。这里的基础概念 是BeanFactory,它提供Factory模式的经典实现来消除对程序单例模式的需要,并真正地允许你从程序逻辑中分离出依赖关系和配置。
- Core模块主要包含Spring框架基本的核心工具类,Spring的其他组件都要使用到这个包里的类,Core模块是其他组件的基本核心。当然你也可以在自己的应用系统中使用这些工具类。
- Beans模块是所有应用都要用到的,它包含访问配置文件,创建和管理bean以及进行Inversion of Control/Dependency Injection(依赖注入)操作相关的所有类。
- Context模块构建于Core和Beans模块基础之上,提供了一种类似于JNDI注册器的框架式的对象访问方法。Context模块集成了Beans的特性,为Spring核心提供了大量的扩展,添加了对国际化(例如资源绑定),事件传播,资源加载和对Context的透明创建的支持。Context模块同时也支持J2EE的一些特性,例如EJB(java企业Bean),JMX(Java Management Extensions,即Java管理扩展是一个为应用程序、设备、系统等植入管理功能的框架)和基础的远程处理。ApplicationContext接口是Context模块的关键。
- Expression Language 模块提供了一个强大的表达式语言用于在运行时查询和操纵对象。它是JSP2.1规范中定义的unifed expression language的一个扩展。该语言支持设置/获取属性的值,属性的分配,方法的调用,访问数组上下文(accession the context of arrays),容器和索引器,逻辑和算数运算符,命名变量以及从Spring的IOC容器中根据名称检索对象。它也支持list投影,选择和一般的list聚合。
(2)WEB层:
Web上下文模块建立在应用程序上下文模块之上,为基于Web的应用程序提供了上下文。所以Spring框架支持与Jakarta Struts的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。Web层包含了Web,Web-Servlet,Web-Struts和Web-Porlet模块,具体说明如下。
- Web-Servlet模块web.servlet.jar:该模块包含Spring的model-view-controller(MVC)的实现。Spring的MVC框架使得模型范围内的代码和web forms之间能够清楚地分离开来,并与Spring框架的其他特性集成在一起。
- Web模块:提供了基础的面向Web的集成特性。例如,多文件上传,使用servlet listeners初始化IOC容器以及一个面向Web的应用上下文。它还包含Spring远程支持中Web的相关部分。
- Web-Porlet模块:提供了用于Portlet环境和Web-Servlet模块的MVC的实现。
- spring4.0以后加入了对websocket技术的支持.目的是浏览器与服务端建立全双工的通信方式,解决http请求-响应带来过多的资源消耗,同时对特殊场景应用提供了全新的实现方式,比如聊天、股票交易、游戏等对对实时性要求较高的行业领域。
(3)Data Access/Integration.持久层:
Data Access/Integration层包含有JDBC,ORM,OXM,JMS和Transaction模块,其中:
- JDBC模块提供了一个JDBC抽象层,它可以消除冗长的JDBC编码和解析数据库厂商特有的错误代码。这个模块包含了Spring对JDBC数据访问进行封装的所有类。
- ORM(Object Relational Mapping对象关系映射)模块为流行的对象-关系映射API,如JPA,JDO,Hibernate,iBatis等,提供了一个交互层。利用ORM封装包,可以混合使用所有Spring提供的特性进行O/R映射。如前边提到的简单声明性事务管理。
Spring框架插入了若干个ORM框架,从而提供了ORM的对象关系工具,其中包括JDO,hibernate和MyBatis。所有这些都遵从Spring的通用事务和DAO异常层次结构。
- OXM模块提供了一个对Object/XML映射实现的抽象层,Object/XML映射实现包括JAXB(JAXB能够使用Jackson对JAXB注解的支持实现(jackson-module-jaxb-annotations),既方便生成XML,也方便生成JSON,这样一来可以更好的标志可以转换为JSON对象的JAVA类。
- JMS(Java Messaging Service)模块主要包含了一些制造和消费消息的特性。
- Transaction模块支持编程和声明性的事务管理,这些事务类必须实现特定的接口,并且对所有的POJO(实际就是普通JavaBeans)都适用。
(4)切面层:
1. AOP模块提供了一个符合AOP联盟标准的面向切面编程的实现,它让你可以定义例如方法拦截器和切点。从而将逻辑代码分开,降低它们之间的耦合性。利用source-level的元数据功能,还可以将各种行为信息合并到你的代码中,这有点像.Net技术中的attribute概念。
通过配置管理特性,SpringAOP模块直接将面向切面的编程功能集成到了Spring框架中,所以可以很容易地使Spring框架管理的任何对象支持AOP。Spring AOP模块为基于Spring的应用程序中的对象提供了事务管理服务。通过使用Spring AOP,不用依赖EJB组件,就可以将声明性事务管理集成到应用程序中。
2. Aspects模块提供了对AspectJ(一个面向切面的框架,它扩展了Java语言)的集成支持。
3.Instrumentation模块提供了class instrumentation 支持和classloader实现,使得可以在特定的应用服务器上使用。
(5)Test层:
此层支持使用JUnit和TestNG对Spring组件进行测试。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/spring/spring-*.xml")
二、以Bean为核心的IOC/DI机制:
总述理论核心:在spring中,所有的对象都会被spring核心容器管理。一切对象统称为Bean。
Spring容器可通过XML配置文件或者注解去管理这堆Bean。
(1)定义以及原理:
依赖注入(IOC/DI):spring容器负责将被依赖对象赋值给调用者的成员变量–相当于为调用者注入它依赖的实例。
依赖关系:A对象需要调用B对象方法的情况–A依赖B。
原理:
1. 原始做法:调用者主动创建被依赖对象,然后再调用被依赖对象的方法。
调用者需要通过像“new 对象”的操作去创建对象。
缺点:必然导致调用者与被依赖对象实现类的硬编码耦合。(因为我不想知道你的创建过程、也不想主动去创建你)
2. 简单工厂模式:调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖对象,最后再调用被依赖对象的方法。
调用者面向被依赖对象的接口编程;将被依赖对象的创建交给工厂;调用者通过工厂来获得被依赖组件。
缺点:调用组件需要主动通过工厂去获取被依赖对象,必然带来调用组件与被依赖对象工厂的耦合。(同样,我也不想知道你这个工厂存在,我只想要个依赖对象)
3.Spring框架下的依赖注入:框架为调用者注入它依赖的实例。
优点:程序无须例会被依赖对象的实现,也无须主动定位工厂。只需被动等待IOC容器分配依赖对象。
(2)应用:
依赖注入分为两种:[一]设值注入;[二]构造注入;
1. 设值注入:指IOC容器通过成员遍历的setter方法来注入被依赖对象。
使用方法:可见我们没有硬编码上去创建依赖对象
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="chinese" class="com.fuzhu.Chinese">
<property name="axe" ref="stoneAxe"/>
</bean>
<bean id="axe" class="com.fuzhu.Axe"/>
</beans>
public class Chinese
{
private Axe axe;
public void setAxe(Axe axe)
{
this.axe = axe;
}
public void useAxe()
{
System.out.println(axe.chop());
}
}
public class Axe
{
public String chop()
{
return "石斧砍柴好慢";
}
}
写个test类
public class BeanTest
{
public static void main(String[] args)throws Exception
{
ApplicationContext ctx = new
ClassPathXmlApplicationContext("beans.xml");
Chinese p = ctx.getBean("chinese" , Chinese.class);
p.useAxe();
}
}
2. 构造注入:IOC容器使用构造器来注入被依赖对象。
在构造实例时,已经为其完成了依赖关系的初始化。本质就是当执行带参数的构造器时,就可利用构造器参数对成员变量执行初始化。《contructopr-arg… /》
使用方法:
<?xml version="1.0" encoding="GBK"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="chinese" class="com.fuzhu.Chinese">
<constructor-arg ref="axe" type="com.fuzhu.Axe"/>
</bean>
<bean id="axe" class="com.fuzhu.StoneAxe"/>
</beans>
public class Chinese
{
private Axe axe;
public Chinese(Axe axe)
{
this.axe = axe;
}
public void useAxe()
{
System.out.println(axe.chop());
}
}
public class Axe
{
public String chop()
{
return "石斧砍柴好慢";
}
}
3. 注解注入装配: 以后再讲,其实是基于前两种注解方式实现的。
(3)IOC/DI依赖注入源码理解:(基于spring4.1.7)
重点理解两个过程:IoC容器初始化过程以及IoC容器依赖注入过程。
其实就是:资源定位、资源装载、资源解析、Bean生成,Bean注册、Bean依赖注入这几个过程(前五属于初始化过程)。方法:eclipse断点ClassPathXmlApplicationContext调用,不断跳进去,就看到spring执行栈了。
1. IoC容器初始化过程:
以上图思路进行详细讲述
初始化总过程:资源定位(确定工厂创建和bean的配置文件)—>资源装载(在文件系统路径上对IOC配置文件、bean配置进行加载)—>资源解析(解析bean配置,解析xml元素)—>生成bean(根据DOM资源解析成bean)—>在IoC容器中注册(交给IoC容器管理,还有依赖注入的权限)
整体过程大致如上图(从下往上看的栈,):保存配置,并刷新工厂–>创建载入BeanFactory–>创建XmlBeanDefinitionReader–>创建处理每一个Resource–>转换成Document对象–>处理XML每个元素–>解析注册bean
[一]资源定位:
追踪:我们可在此句获取工厂前设断点然后debug追踪进去,查看IoC的资源定位
ApplicationContext ctx = new ClassPathXmlApplicationContext("/spring/spring-*.xml");
然后一路跳进去:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if(refresh) {
this.refresh();
}
}
public AbstractXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
public void setConfigLocation(String location) {
this.setConfigLocations(StringUtils.tokenizeToStringArray(location, ",; \t\n"));
}
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] = this.resolvePath(locations[i]).trim();
}
} else {
this.configLocations = null;
}
}
根据资源定位核心调用层,我们可以看到他必执行AbstractApplicationContext中的refresh方法,执行容器刷新。部分叙述参考此博主此文章
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var5) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt", var5);
this.destroyBeans();
this.cancelRefresh(var5);
throw var5;
}
}
}
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if(this.logger.isDebugEnabled()) {
this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
AbstractRefreshableApplicationContext实现的refreshBeanFactory
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);
}
}
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.active.set(true);
if(this.logger.isInfoEnabled()) {
this.logger.info("Refreshing " + this);
}
this.initPropertySources();
this.getEnvironment().validateRequiredProperties();
}
总的来说:资源定位做的就是:确定工厂位置,执行工厂初始化并刷新,建立好bean资源加载路径。等待bean资源装载。
[二]资源装载
设置工厂配置,刷新容器后,还要把我们的bean配置给资源加载器。
目标:拿到资源加载器,可以classpath:那样直接拿到资源装载。
在这之前,很有必要大家一起区分:不同类中的loadBeanDefinitions解析职责。
在AbstractXmlApplicationContext类中,职责为:对applicationContext.xml的解析操作,就是解析工厂的那个xml
在AbstractBeanDefinitionReader类中,职责为:从指定的资源加载bean定义,真正实现在其子类,这里是做了些兼容性错误处理。
在XmlBeanDefinitionReader类中,是AbstractBeanDefinitionReader的子类,而且是一个真正的实现类 ,是实现BeanDefinitionReader接口的loadBeanDefinitions(Resource var1) 等方法的关键解析类。职责为:读取并真正解析 xml 文件。
AbstractRefreshableApplicationContext中只定义了抽象的loadBeanDefinitions方法,容器真正调用的是其子类AbstractXmlApplicationContext对该方法的实现。(全局搜索SHIFT)
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
this.loadBeanDefinitions(beanDefinitionReader);
}
由上面代码得知进入AbstractXmlApplicationContext的loadBeanDefinitions(XmlBeanDefinitionReader参数)
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = this.getConfigResources();
if(configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = this.getConfigLocations();
if(configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
接着根据上面继续追踪,到了AbstractBeanDefinitionReader类的loadBeanDefinitions方法
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = this.getResourceLoader();
if(resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
} else {
int loadCount;
if(!(resourceLoader instanceof ResourcePatternResolver)) {
Resource resource = resourceLoader.getResource(location);
loadCount = this.loadBeanDefinitions((Resource)resource);
if(actualResources != null) {
actualResources.add(resource);
}
return loadCount;
} else {
try {
Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
loadCount = this.loadBeanDefinitions(resources);
if(actualResources != null) {
Resource[] var6 = resources;
int var7 = resources.length;
for(int var8 = 0; var8 < var7; ++var8) {
Resource resource = var6[var8];
actualResources.add(resource);
}
}
if(this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
} catch (IOException var10) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
}
}
}
}
所以,AbstractBeanDefinitionReader的loadBeanDefinitions方法源码分析可以看出该方法做了以下两件事:
(1)首先,调用资源加载器的获取资源方法resourceLoader.getResource(location),获取到要加载的资源。
(2)其次,真正执行加载功能是其子类XmlBeanDefinitionReader实现的loadBeanDefinitions方法。
另外,此时调用的是DefaultResourceLoader中的getSource()方法定位Resource。
然后我们再仔细看下各个类想拿到资源加载器就是通过getResourceLoader,拿到AbstractBeanDefinitionReader类定义的resourceLoader。这样的话,我们可通过此方式在工程spring下的任何地方拿到资源加载器,“随处加载”了。
public interface ResourceLoader {
String CLASSPATH_URL_PREFIX = "classpath:";
Resource getResource(String var1);
ClassLoader getClassLoader();
}
总的来说,资源装载就是:根据之前确定好的bean资源配置路径,拿到资源、拿到加载器,并把bean配置丢进XmlBeanDefinitionReader。等待Bean资源解析。
[三]Bean资源解析:其实就是刚我们遇到的XmlBeanDefinitionReader类啦。真正去解析xml。解析的关注重心请注意到doLoadBeanDefinitions方法,从这里进行分发。从而到下一部生成bean对象。
目标:将XML文件转为DOM对象。进而交DocumentLoader和DocumentBuilderFactory处理dom对象给doLoadBeanDefinitions方法,从而为bean生成作铺垫
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if(this.logger.isInfoEnabled()) {
this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if(currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if(!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if(encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
inputStream.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if(((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
Document doc = this.doLoadDocument(inputSource, resource);
return this.registerBeanDefinitions(doc, resource);
} catch (BeanDefinitionStoreException var4) {
throw var4;
} catch (SAXParseException var5) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
} catch (SAXException var6) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
} catch (ParserConfigurationException var7) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
} catch (IOException var8) {
throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
} catch (Throwable var9) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
}
}
然后沿着doLoadDocument继续追踪,追踪到一个接口DocumentLoader和一个实现类DefaultDocumentLoader。以下是DefaultDocumentLoader这个实现类的部分代码
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = this.createDocumentBuilderFactory(validationMode, namespaceAware);
if(logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
DocumentBuilder builder = this.createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory, EntityResolver entityResolver, ErrorHandler errorHandler) throws ParserConfigurationException {
DocumentBuilder docBuilder = factory.newDocumentBuilder();
if(entityResolver != null) {
docBuilder.setEntityResolver(entityResolver);
}
if(errorHandler != null) {
docBuilder.setErrorHandler(errorHandler);
}
return docBuilder;
}
总的来说:Bean资源解析就是,先通过 XML解析器讲Bean定义资源文件转换得到Document对象,但是这堆Document对象没有按照spring的Bean规则的,所以不可直接转换成bean对象。然后完成XML解析变成Document对象后,就调用spring的解析方法按照Spring的Bean规则去对Document进行解析,生成Bean对象。
[四]生成Bean:还是关注XmlBeanDefinitionReader类的doLoadBeanDefinitions方法,他进行了一个调用:registerBeanDefinitions。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
int countBefore = this.getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
return this.getRegistry().getBeanDefinitionCount() - countBefore;
}
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return (BeanDefinitionDocumentReader)BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
接下来就是document元素的一个个解析,然后转化成bean对象了。我们根据上面的解析入口可以追踪到 BeanDefinitionDocumentReader接口的实现类DefaultBeanDefinitionDocumentReader。在这个类进行详细的document元素解析成我们平常工程用的bean。但本博主不打算继续看了,因为对我们掌握spring的IOC原理并不影响。
[五]在IoC容器注册解析生成的Bean:
目标:到IoC容器注册
我们能猜到他在类DefaultBeanDefinitionDocumentReader生成bean后必然会丢给IoC容器去注册,交给它管理。但是我们怎么找到呢??根据上面生成bean中的解析入口,我们CTRL+F查registerBeanDefinitions。
再进一步追踪到parseDefaultElement方法,可以看到这里就是识别主标签,从而进行解析生成bean。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if(delegate.nodeNameEquals(ele, "import")) {
this.importBeanDefinitionResource(ele);
} else if(delegate.nodeNameEquals(ele, "alias")) {
this.processAliasRegistration(ele);
} else if(delegate.nodeNameEquals(ele, "bean")) {
this.processBeanDefinition(ele, delegate);
} else if(delegate.nodeNameEquals(ele, "beans")) {
this.doRegisterBeanDefinitions(ele);
}
}
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if(bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
} catch (BeanDefinitionStoreException var5) {
this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
}
this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
String[] aliases = definitionHolder.getAliases();
if(aliases != null) {
String[] var4 = aliases;
int var5 = aliases.length;
for(int var6 = 0; var6 < var5; ++var6) {
String alias = var4[var6];
registry.registerAlias(beanName, alias);
}
}
}
终于找到非抽象实现类啦:DefaultListableBeanFactory(其实我当时查的快疯,是查他的继承树才查到这个的。)
使用一个HashMap的集合对象存放IoC容器中注册解析的BeanDefinition
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");
if(beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition)beanDefinition).validate();
} catch (BeanDefinitionValidationException var4) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var4);
}
}
BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
if(oldBeanDefinition != null) {
if(!this.isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
}
if(oldBeanDefinition.getRole() < beanDefinition.getRole()) {
if(this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-define d bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
} else if(this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
}
} else {
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
this.frozenBeanDefinitionNames = null;
}
this.beanDefinitionMap.put(beanName, beanDefinition);
if(oldBeanDefinition != null || this.containsSingleton(beanName)) {
this.resetBeanDefinition(beanName);
}
}
总的来说就是:把beandefinition丢给工厂用hashmap存好。
IOC容器初始化总结:
(1)通过setConfigLocations载入spring配置文件;
(2)初始化容器入口通过refresh方法,进入AbstractApplicationContext实现的refresh方法。
(3)然后通过obtainFreshBeanFactory方法进入子类AbstractRefreshableApplicationContext实现的refreshBeanFactory刷新一个容器工厂
(4)在此创建了DefaultListableBeanFactory类,并调用loadBeanDefinitions(beanFactory)装载bean定义
(5)接着以AbstractRefreshableApplicationContext为中心回到此类,进入其子类AbstractXmlApplicationContext实现的loadBeanDefinitions方法。对applicationContext.xml的解析操作,就是解析工厂的那个xml。
(6)再接着通过AbstractXmlApplicationContext的loadBeanDefinitions进入到AbstractBeanDefinitionReader类的loadBeanDefinitions。通过获取资源方法resourceLoader.getResource(location),获取到要加载的资源。再真正执行加载功能是其子类XmlBeanDefinitionReader实现的loadBeanDefinitions方法。
(6)接着进入XmlBeanDefinitionReader中的loadBeanDefinitions。(XmlBeanDefinitionReader通过调用其父类中调用的DefaultResourceLoader的getResource方法获取要加载的资源)DocumentLoader将Bean定义资源转换成Document对象。
(7)doLoadBeanDefinitions中进入DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions 解 析 D ocument对象
(8)解析完后,调用DefaultListableBeanFactory类中使用一个HashMap的集合对象存放IoC容器中注册解析的BeanDefinition
2.IoC容器依赖注入过程:
[ 一 ]先来读懂beanfactory的继承逻辑树
类图。我们根据DefaultListableBeanFactory继续追踪上去。一会详讲此逻辑线。参考此博主此文章,非常感谢他,写得太棒了。让我学到很多。
先来读懂它beanfactory的继承树逻辑线。图取自此文章
解析上图:
BeanFactory是Spring的最根的接口,类的工厂接口。HierarchicalBeanFactory接口是在继承BeanFactory的基础上,实现BeanFactory的父子关系。Hierarchical表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean。
AutowireCapableBeanFactory接口是在继承BeanFactory的基础上,实现Bean的自动装配功能。定义 Bean 的自动装配规则。
ListableBeanFactory接口是在继承BeanFactory的基础上,实现Bean的list集合操作功能。表示这些 Bean 是可列表的。
ConfigurableBeanFactory接口是在继承HierarchicalBeanFactory的基础上,实现BeanFactory的全部配置管理功能, SingletonBeanRegistry是单例bean的注册接口
ConfigurableListableBeanFactory接口是继承AutowireCapableBeanFactory,ListableBeanFactory,ConfigurableBeanFactory三个接口的一个综合接口。
AliasRegistry接口是别名注册接口,SimpleAliasRegistry类是简单的实现别名注册接口的类。
DefaultSingletonBeanRegistry是默认的实现SingletonBeanRegistry接口的类,同时,继承类SimpleAliasRegistry 。
FactoryBeanRegistrySupport是实现FactoryBean注册的功能实现。继承类DefaultSingletonBeanRegistry 。负责FactoryBean相关的操作,并缓存FactoryBean的getObject实例化的bean. 判断factory是单例,同时已经new好了单例时,先尝试去缓存找;如果找不到或者不是单例,委托doGetObjectFromFactoryBean实例化一个。
AbstractBeanFactory是部分实现接口ConfigurableBeanFactory,并继承类FactoryBeanRegistrySupport 。这个是最顶层的抽象IOC容器空构造器,主要用来具体实现了BeanFactory接口。
AbstractAutowireCapableBeanFactory是实现接口AutowireCapableBeanFactory,并继承类 AbstractBeanFactory 。主要的功能就是实现了默认的bean创建方法createBean().而在这个创建过程中,提供了诸如bean的属性注入,初始化方法的调用,自动装配的实现,bean处理器的调用。
DefaultListableBeanFactory实现接口 ConfigurableListableBeanFactory、BeanDefinitionRegistry(bean定义的注册接口), 并继承AbstractAutowireCapableBeanFactory,实现全部类管理的功能。
可以看出DefaultListableBeanFactory就是springIoC机制的入口。
[二]IoC容器依赖注入源码详讲:上面可知我们从实现BeanFactory的AbstractBeanFactory入手
1.我们从DefaultListableBeanFactory开始不断追踪父类,直到找到了AbstractBeanFactory。
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
final String beanName = this.transformedBeanName(name);
Object sharedInstance = this.getSingleton(beanName);
Object bean;
if(sharedInstance != null && args == null) {
if(this.logger.isDebugEnabled()) {
if(this.isSingletonCurrentlyInCreation(beanName)) {
this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");
} else {
this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
} else {
if(this.isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = this.getParentBeanFactory();
if(parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {
String nameToLookup = this.originalBeanName(name);
if(args != null) {
return parentBeanFactory.getBean(nameToLookup, args);
}
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
if(!typeCheckOnly) {
this.markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);
this.checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
String[] var11;
if(dependsOn != null) {
var11 = dependsOn;
int var12 = dependsOn.length;
for(int var13 = 0; var13 < var12; ++var13) {
String dependsOnBean = var11[var13];
if(this.isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
}
this.registerDependentBean(dependsOnBean, beanName);
this.getBean(dependsOnBean);
}
}
if(mbd.isSingleton()) {
sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return AbstractBeanFactory.this.createBean(beanName, mbd, args);
} catch (BeansException var2) {
AbstractBeanFactory.this.destroySingleton(beanName);
throw var2;
}
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} else if(mbd.isPrototype()) {
var11 = null;
Object prototypeInstance;
try {
this.beforePrototypeCreation(beanName);
prototypeInstance = this.createBean(beanName, mbd, args);
} finally {
this.afterPrototypeCreation(beanName);
}
bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} else {
String scopeName = mbd.getScope();
Scope scope = (Scope)this.scopes.get(scopeName);
if(scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
AbstractBeanFactory.this.beforePrototypeCreation(beanName);
Object var1;
try {
var1 = AbstractBeanFactory.this.createBean(beanName, mbd, args);
} finally {
AbstractBeanFactory.this.afterPrototypeCreation(beanName);
}
return var1;
}
});
bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} catch (IllegalStateException var21) {
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", var21);
}
}
} catch (BeansException var23) {
this.cleanupAfterBeanCreationFailure(beanName);
throw var23;
}
}
if(requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return this.getTypeConverter().convertIfNecessary(bean, requiredType);
} catch (TypeMismatchException var22) {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Failed to convert bean '" + name + "' to required type [" + ClassUtils.getQualifiedName(requiredType) + "]", var22);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
} else {
return bean;
}
}
}
我们可以很清晰看到,创建bean的时候所做的判断:
(1)如果Bean定义的单态模式(Singleton),则容器在创建之前先从缓存中查找,以确保整个容器中只存在一个实例对象
(2) 如果Bean定义的是原型模式(Prototype),则容器每次都会创建一个新的实例对象。
(3)两者都不是,则根据Bean定义资源中配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中 比较常用,如:request、session、application等生命周期。
上面的源码只是定义了根据Bean定义的模式,采取的不同创建Bean实例对象的策略,具体的Bean实例对象的创建过程由实现了ObejctFactory接口的匿名内部类的createBean方法完成,ObejctFactory使用委派模式,具体的Bean实例创建过程交由其实现类AbstractAutowireCapableBeanFactory完成,我们继续分析AbstractAutowireCapableBeanFactory的createBean方法的源码,理解其创建Bean实例的具体实现过程
2.因此我们根据上面所述继续追踪,现追踪AbstractBeanFactory的一个匿名内部类的createBean方法,实际上这方法的实现就是在我们从DefaultListableBeanFactory追踪父类过来的途中遇到的AbstractAutowireCapableBeanFactory类,是AbstractBeanFactory子类。
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Creating instance of bean '" + beanName + "'");
}
this.resolveBeanClass(mbd, beanName, new Class[0]);
try {
mbd.prepareMethodOverrides();
} catch (BeanDefinitionValidationException var5) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName, "Validation of method overrides failed", var5);
}
Object beanInstance;
try {
beanInstance = this.resolveBeforeInstantiation(beanName, mbd);
if(beanInstance != null) {
return beanInstance;
}
} catch (Throwable var6) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var6);
}
beanInstance = this.doCreateBean(beanName, mbd, args);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Object[] args) {
BeanWrapper instanceWrapper = null;
if(mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if(instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper != null?instanceWrapper.getWrappedInstance():null;
Class<?> beanType = instanceWrapper != null?instanceWrapper.getWrappedClass():null;
Object var7 = mbd.postProcessingLock;
synchronized(mbd.postProcessingLock) {
if(!mbd.postProcessed) {
this.applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if(earlySingletonExposure) {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
this.addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return AbstractAutowireCapableBeanFactory.this.getEarlyBeanReference(beanName, mbd, bean);
}
});
}
Object exposedObject = bean;
try {
this.populateBean(beanName, mbd, instanceWrapper);
if(exposedObject != null) {
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
}
} catch (Throwable var17) {
if(var17 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var17).getBeanName())) {
throw (BeanCreationException)var17;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var17);
}
if(earlySingletonExposure) {
Object earlySingletonReference = this.getSingleton(beanName, false);
if(earlySingletonReference != null) {
if(exposedObject == bean) {
exposedObject = earlySingletonReference;
} else if(!this.allowRawInjectionDespiteWrapping && this.hasDependentBean(beanName)) {
String[] dependentBeans = this.getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet(dependentBeans.length);
String[] var12 = dependentBeans;
int var13 = dependentBeans.length;
for(int var14 = 0; var14 < var13; ++var14) {
String dependentBean = var12[var14];
if(!this.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.");
}
}
}
}
try {
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
} catch (BeanDefinitionValidationException var16) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", var16);
}
}
上面还是一堆校验以及状态判断。
其中真正实现是分发到:
createBeanInstance:生成Bean所包含的Java对象实例。
populateBean :对Bean属性的依赖注入进行处理。
3.那么我们来看下createBeanInstance方法的代码,还是在AbstractAutowireCapableBeanFactory类中。
在此方法中,根据指定的初始化策略,使用静态工厂、工厂方法或者容器的自动装配特性生成java实例对象。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
Class<?> beanClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
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());
} else if(mbd.getFactoryMethodName() != null) {
return this.instantiateUsingFactoryMethod(beanName, mbd, args);
} else {
boolean resolved = false;
boolean autowireNecessary = false;
if(args == null) {
Object var7 = mbd.constructorArgumentLock;
synchronized(mbd.constructorArgumentLock) {
if(mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if(resolved) {
return autowireNecessary?this.autowireConstructor(beanName, mbd, (Constructor[])null, (Object[])null):this.instantiateBean(beanName, mbd);
} else {
Constructor<?>[] ctors = this.determineConstructorsFromBeanPostProcessors(beanClass, beanName);
return ctors == null && mbd.getResolvedAutowireMode() != 3 && !mbd.hasConstructorArgumentValues() && ObjectUtils.isEmpty(args)?this.instantiateBean(beanName, mbd):this.autowireConstructor(beanName, mbd, ctors, args);
}
}
}
上面看到一个无参构造器:instantiateBean
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
if(System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return AbstractAutowireCapableBeanFactory.this.getInstantiationStrategy().instantiate(mbd, beanName, AbstractAutowireCapableBeanFactory.this);
}
}, this.getAccessControlContext());
} else {
beanInstance = this.getInstantiationStrategy().instantiate(mbd, beanName, this);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
this.initBeanWrapper(bw);
return bw;
} catch (Throwable var6) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", var6);
}
}
4.我们都看到了,无论什么调用什么构造器,返回的都是统一的BeanWrapper
BeanWrapper是什么贵?org.springframework.beans.BeanWrapper是Spring框架中重要的组件类。BeanWrapper相当于一个代理器,Spring通过BeanWrapper完成Bean属性的填充工作。在Bean实例被InstantiationStrategy创建出来之后,容器主控程序将Bean实例通过BeanWrapper包装起来。
由于它是接口,必然有个实现类,实现依赖注入的具体实现。那就是BeanWrapperImpl,它的作用是:(1)Bean包裹器;(2)属性访问器;(3)属性编辑器注册表。
5.我们接着回到createBean,它还有个实现分发populateBean 方法:对Bean属性的依赖注入进行处理
过程是两部分:属性值解析和注入
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
if(bw == null) {
if(!((PropertyValues)pvs).isEmpty()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
} else {
boolean continueWithPropertyPopulation = true;
if(!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
Iterator var6 = this.getBeanPostProcessors().iterator();
while(var6.hasNext()) {
BeanPostProcessor bp = (BeanPostProcessor)var6.next();
if(bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
if(!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if(continueWithPropertyPopulation) {
if(mbd.getResolvedAutowireMode() == 1 || mbd.getResolvedAutowireMode() == 2) {
MutablePropertyValues newPvs = new MutablePropertyValues((PropertyValues)pvs);
if(mbd.getResolvedAutowireMode() == 1) {
this.autowireByName(beanName, mbd, bw, newPvs);
}
if(mbd.getResolvedAutowireMode() == 2) {
this.autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = this.hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = mbd.getDependencyCheck() != 0;
if(hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = this.filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if(hasInstAwareBpps) {
Iterator var9 = this.getBeanPostProcessors().iterator();
while(var9.hasNext()) {
BeanPostProcessor bp = (BeanPostProcessor)var9.next();
if(bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
pvs = ibp.postProcessPropertyValues((PropertyValues)pvs, filteredPds, bw.getWrappedInstance(), beanName);
if(pvs == null) {
return;
}
}
}
}
if(needsDepCheck) {
this.checkDependencies(beanName, mbd, filteredPds, (PropertyValues)pvs);
}
}
this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
}
}
}
6.那么我们继续追踪applyPropertyValues方法
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if(pvs != null && !pvs.isEmpty()) {
MutablePropertyValues mpvs = null;
if(System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl)bw).setSecurityContext(this.getAccessControlContext());
}
List original;
if(pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues)pvs;
if(mpvs.isConverted()) {
try {
bw.setPropertyValues(mpvs);
return;
} catch (BeansException var18) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var18);
}
}
original = mpvs.getPropertyValueList();
} else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = this.getCustomTypeConverter();
if(converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, (TypeConverter)converter);
List<PropertyValue> deepCopy = new ArrayList(original.size());
boolean resolveNecessary = false;
Iterator var11 = original.iterator();
while(true) {
while(var11.hasNext()) {
PropertyValue pv = (PropertyValue)var11.next();
if(pv.isConverted()) {
deepCopy.add(pv);
} else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if(convertible) {
convertedValue = this.convertForProperty(resolvedValue, propertyName, bw, (TypeConverter)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));
return;
} catch (BeansException var19) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var19);
}
}
}
}
总结applyPropertyValues方法(完成属性转换):
属性值类型不需要转换时,不需要解析属性值,直接准备进行依赖注入。
属性值需要进行类型转换时,如对其他对象的引用等,首先需要解析属性值,然后对解析后的属性值进行依赖注入。
而且我们看到调用了resolveValueIfNecessary方法对属性值的解析
7.追踪resolveValueIfNecessary,发现是在BeanDefinitionValueResolver类
当容器在对属性进行依赖注入时,如果发现属性值需要进行类型转换,如属性值是容器中另一个Bean实例对象的引用,则容器首先需要根据属性值解析出所引用的对象,然后才能将该引用对象注入到目标实例对象的属性上去,对属性进行解析的由resolveValueIfNecessary方法实现。
可知:创建与注入是个递归的过程
public Object resolveValueIfNecessary(Object argName, Object value) {
if(value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference)value;
return this.resolveReference(argName, ref);
} else if(value instanceof RuntimeBeanNameReference) {
String refName = ((RuntimeBeanNameReference)value).getBeanName();
refName = String.valueOf(this.doEvaluate(refName));
if(!this.beanFactory.containsBean(refName)) {
throw new BeanDefinitionStoreException("Invalid bean name '" + refName + "' in bean reference for " + argName);
} else {
return refName;
}
} else if(value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder)value;
return this.resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
} else if(value instanceof BeanDefinition) {
BeanDefinition bd = (BeanDefinition)value;
String innerBeanName = "(inner bean)#" + ObjectUtils.getIdentityHexString(bd);
return this.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 var9) {
throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error resolving array type for " + argName, var9);
}
} else {
elementType = Object.class;
}
}
return this.resolveManagedArray(argName, (List)value, elementType);
} else if(value instanceof ManagedList) {
return this.resolveManagedList(argName, (List)value);
} else if(value instanceof ManagedSet) {
return this.resolveManagedSet(argName, (Set)value);
} else if(value instanceof ManagedMap) {
return this.resolveManagedMap(argName, (Map)value);
} else if(value instanceof ManagedProperties) {
Properties original = (Properties)value;
Properties copy = new Properties();
Object propKey;
Object propValue;
for(Iterator var19 = original.entrySet().iterator(); var19.hasNext(); copy.put(propKey, propValue)) {
Entry<Object, Object> propEntry = (Entry)var19.next();
propKey = propEntry.getKey();
propValue = propEntry.getValue();
if(propKey instanceof TypedStringValue) {
propKey = this.evaluate((TypedStringValue)propKey);
}
if(propValue instanceof TypedStringValue) {
propValue = this.evaluate((TypedStringValue)propValue);
}
}
return copy;
} else if(value instanceof TypedStringValue) {
TypedStringValue typedStringValue = (TypedStringValue)value;
Object valueObject = this.evaluate(typedStringValue);
try {
Class<?> resolvedTargetType = this.resolveTargetType(typedStringValue);
return resolvedTargetType != null?this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType):valueObject;
} catch (Throwable var10) {
throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Error converting typed String value for " + argName, var10);
}
} else {
return this.evaluate(value);
}
}
刚也说了解析引用类型是特殊的:resolveReference方法
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
String refName = ref.getBeanName();
refName = String.valueOf(this.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");
} else {
return this.beanFactory.getParentBeanFactory().getBean(refName);
}
} else {
Object bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
}
} catch (BeansException var5) {
throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName, "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, var5);
}
}
8.并且我们注意到applyPropertyValues方法(刚刚的AbstractAutowireCapableBeanFactory类)中,分发了一个方法实现对属性值的依赖注入setPropertyValues
前面也说到BeanWrapper接口的实现类就是BeanWrapperImpl。一系列的依赖注入都在这个里面,那么我们往上查找PropertyAccessor接口,并且发现路过的抽象类AbstractPropertyAccessor,终于找到了setPropertyValues方法的实现,有个模板模式,就是调用在AbstractPropertyAccessor中的抽象方法setPropertyValue(此方法在BeanWrapperImpl实现了!!)
private void setPropertyValue(BeanWrapperImpl.PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
String propertyName = tokens.canonicalName;
String actualName = tokens.actualName;
Object propValue;
if(tokens.keys != null) {
BeanWrapperImpl.PropertyTokenHolder getterTokens = new BeanWrapperImpl.PropertyTokenHolder(null);
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);
try {
propValue = this.getPropertyValue(getterTokens);
} catch (NotReadablePropertyException var21) {
throw new NotWritablePropertyException(this.getRootClass(), this.nestedPath + propertyName, "Cannot access indexed value in property referenced in indexed property path '" + propertyName + "'", var21);
}
String key = tokens.keys[tokens.keys.length - 1];
if(propValue == null) {
if(!this.isAutoGrowNestedPaths()) {
throw new NullValueInNestedPathException(this.getRootClass(), this.nestedPath + propertyName, "Cannot access indexed value in property referenced in indexed property path '" + propertyName + "': returned null");
}
int lastKeyIndex = tokens.canonicalName.lastIndexOf(91);
getterTokens.canonicalName = tokens.canonicalName.substring(0, lastKeyIndex);
propValue = this.setDefaultValue(getterTokens);
}
Object convertedValue;
Object newArray;
Class requiredType;
PropertyDescriptor pd;
if(propValue.getClass().isArray()) {
pd = this.getCachedIntrospectionResults().getPropertyDescriptor(actualName);
requiredType = propValue.getClass().getComponentType();
int arrayIndex = Integer.parseInt(key);
Object oldValue = null;
try {
if(this.isExtractOldValueForEditor() && arrayIndex < Array.getLength(propValue)) {
oldValue = Array.get(propValue, arrayIndex);
}
convertedValue = this.convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType, TypeDescriptor.nested(this.property(pd), tokens.keys.length));
int length = Array.getLength(propValue);
if(arrayIndex >= length && arrayIndex < this.autoGrowCollectionLimit) {
Class<?> componentType = propValue.getClass().getComponentType();
newArray = Array.newInstance(componentType, arrayIndex + 1);
System.arraycopy(propValue, 0, newArray, 0, length);
this.setPropertyValue(actualName, newArray);
propValue = this.getPropertyValue(actualName);
}
Array.set(propValue, arrayIndex, convertedValue);
} catch (IndexOutOfBoundsException var20) {
throw new InvalidPropertyException(this.getRootClass(), this.nestedPath + propertyName, "Invalid array index in property path '" + propertyName + "'", var20);
}
} else {
Object convertedValue;
if(propValue instanceof List) {
pd = this.getCachedIntrospectionResults().getPropertyDescriptor(actualName);
requiredType = GenericCollectionTypeResolver.getCollectionReturnType(pd.getReadMethod(), tokens.keys.length);
List<Object> list = (List)propValue;
int index = Integer.parseInt(key);
convertedValue = null;
if(this.isExtractOldValueForEditor() && index < list.size()) {
convertedValue = list.get(index);
}
convertedValue = this.convertIfNecessary(propertyName, convertedValue, pv.getValue(), requiredType, TypeDescriptor.nested(this.property(pd), tokens.keys.length));
int size = list.size();
if(index >= size && index < this.autoGrowCollectionLimit) {
for(int i = size; i < index; ++i) {
try {
list.add((Object)null);
} catch (NullPointerException var19) {
throw new InvalidPropertyException(this.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 var18) {
throw new InvalidPropertyException(this.getRootClass(), this.nestedPath + propertyName, "Invalid list index in property path '" + propertyName + "'", var18);
}
}
} else {
if(!(propValue instanceof Map)) {
throw new InvalidPropertyException(this.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 + "]");
}
pd = this.getCachedIntrospectionResults().getPropertyDescriptor(actualName);
requiredType = GenericCollectionTypeResolver.getMapKeyReturnType(pd.getReadMethod(), tokens.keys.length);
Class<?> mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(pd.getReadMethod(), tokens.keys.length);
Map<Object, Object> map = (Map)propValue;
TypeDescriptor typeDescriptor = TypeDescriptor.valueOf(requiredType);
convertedValue = this.convertIfNecessary((String)null, (Object)null, key, requiredType, typeDescriptor);
Object oldValue = null;
if(this.isExtractOldValueForEditor()) {
oldValue = map.get(convertedValue);
}
newArray = this.convertIfNecessary(propertyName, oldValue, pv.getValue(), mapValueType, TypeDescriptor.nested(this.property(pd), tokens.keys.length));
map.put(convertedValue, newArray);
}
}
} else {
PropertyDescriptor pd = pv.resolvedDescriptor;
if(pd == null || !pd.getWriteMethod().getDeclaringClass().isInstance(this.object)) {
pd = this.getCachedIntrospectionResults().getPropertyDescriptor(actualName);
if(pd == null || pd.getWriteMethod() == null) {
if(pv.isOptional()) {
logger.debug("Ignoring optional value for property '" + actualName + "' - property not found on bean class [" + this.getRootClass().getName() + "]");
return;
}
PropertyMatches matches = PropertyMatches.forProperty(propertyName, this.getRootClass());
throw new NotWritablePropertyException(this.getRootClass(), this.nestedPath + propertyName, matches.buildErrorMessage(), matches.getPossibleMatches());
}
pv.getOriginalPropertyValue().resolvedDescriptor = pd;
}
propValue = null;
PropertyChangeEvent propertyChangeEvent;
try {
Object originalValue = pv.getValue();
Object valueToApply = originalValue;
final Method readMethod;
if(!Boolean.FALSE.equals(pv.conversionNecessary)) {
if(pv.isConverted()) {
valueToApply = pv.getConvertedValue();
} else {
if(this.isExtractOldValueForEditor() && pd.getReadMethod() != null) {
readMethod = pd.getReadMethod();
if(!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) && !readMethod.isAccessible()) {
if(System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
readMethod.setAccessible(true);
return null;
}
});
} else {
readMethod.setAccessible(true);
}
}
try {
if(System.getSecurityManager() != null) {
propValue = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
return readMethod.invoke(BeanWrapperImpl.this.object, new Object[0]);
}
}, this.acc);
} else {
propValue = readMethod.invoke(this.object, new Object[0]);
}
} catch (Exception var22) {
Exception ex = var22;
if(var22 instanceof PrivilegedActionException) {
ex = ((PrivilegedActionException)var22).getException();
}
if(logger.isDebugEnabled()) {
logger.debug("Could not read previous value of property '" + this.nestedPath + propertyName + "'", ex);
}
}
}
valueToApply = this.convertForProperty(propertyName, propValue, originalValue, new TypeDescriptor(this.property(pd)));
}
pv.getOriginalPropertyValue().conversionNecessary = Boolean.valueOf(valueToApply != originalValue);
}
readMethod = pd instanceof GenericTypeAwarePropertyDescriptor?((GenericTypeAwarePropertyDescriptor)pd).getWriteMethodForActualAccess():pd.getWriteMethod();
if(!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) && !readMethod.isAccessible()) {
if(System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
readMethod.setAccessible(true);
return null;
}
});
} else {
readMethod.setAccessible(true);
}
}
final Object value = valueToApply;
if(System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
public Object run() throws Exception {
readMethod.invoke(BeanWrapperImpl.this.object, new Object[]{value});
return null;
}
}, this.acc);
} catch (PrivilegedActionException var17) {
throw var17.getException();
}
} else {
readMethod.invoke(this.object, new Object[]{valueToApply});
}
} catch (TypeMismatchException var23) {
throw var23;
} catch (InvocationTargetException var24) {
propertyChangeEvent = new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, propValue, pv.getValue());
if(var24.getTargetException() instanceof ClassCastException) {
throw new TypeMismatchException(propertyChangeEvent, pd.getPropertyType(), var24.getTargetException());
}
throw new MethodInvocationException(propertyChangeEvent, var24.getTargetException());
} catch (Exception var25) {
propertyChangeEvent = new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, propValue, pv.getValue());
throw new MethodInvocationException(propertyChangeEvent, var25);
}
}
}
很复杂的一个解析方法:将属性的值注入到Bean实例对象中情况如下:
1. 对于集合类型的属性,将其属性值解析为目标类型的集合后直接赋值给属性
2. 对于非集合类型的属性,大量使用了JDK的反射和内省机制,通过属性的getter方法(reader method)获取指定属性注入以前的值,同时调用属性的setter方法(writer method)为属性设置注入后的值。
依赖注入总结:
(一)DefaultListableBeanFactory父类AbstractBeanFactory根据Bean的状态定义(单例、存在、原型)进行构造方法分发。分发到AbstractAutowireCapableBeanFactory类的createBean方法
(二)createBean方法负责Bean实例要求状态判断以及再度分发到doCreateBean实现创建实例(再次配置判断)。并在doCreateBean再度分发去createBeanInstance去Bean所包含的Java对象实例以及去populateBean 方法对Bean属性的依赖注入进行处理(以此为责任分发中心)。
(三)在createBeanInstance方法中真正地根据之前的配置判断设置选择真正合适的构造器(自动装配、无参构造器);
(四)在populateBean 方法中真正地将Bean属性设置到生成的实例对象上 ,但在过程中注入依赖属性的是在applyPropertyValues方法(完成属性转换),调用BeanDefinitionValueResolver类调用resolveValueIfNecessary方法对属性值的解析,属性的真正注入实现在BeanWrapperImpl类。
好了,Spring应用、原理以及粗读源码系列(一)–框架总述、以Bean为核心的机制(IoC容器初始化以及依赖注入)讲完了,这个系列以应用为基本点,结合源码讲解那堆应用的机制原理,我会加快脚步学习,分享经验给大家,希望大家喜欢。欢迎在下面指出错误,共同学习!!你的点赞是对我最好的支持!!
更多内容,可以访问JackFrost的博客