标签:active ext xpl 状态 current 标准 origin 依赖 返回
经过前面的文章分析,我们结束了对XML配置文件的解析,这篇文章开始对bean加载进行分析,话不多说,开始。
下面有很简单的一段代码可以作为Spring代码加载的入口:
1 ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml"); 2 ac.getBean(XXX.class);
ClassPathXmlApplicationContext用于加载CLASSPATH下的Spring配置文件,可以看到,第二行就已经可以获取到Bean的实例了。所以先来分析一下第一句代码,还是对照着源码来分析:
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args) throws BeansException { return doGetBean(name, requiredType, args, false); }
1 protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, 2 @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { 3 //提取对应的beanName 4 final String beanName = transformedBeanName(name); 5 Object bean; 6 7 // 检查缓存中或者实例工厂中是否有对应的实例:尝试直接从缓存中获取或者singletonFactories中的objectFactory中获取 8 Object sharedInstance = getSingleton(beanName); 9 if (sharedInstance != null && args == null) { 10 if (logger.isTraceEnabled()) { 11 if (isSingletonCurrentlyInCreation(beanName)) { 12 logger.trace("Returning eagerly cached instance of singleton bean ‘" + beanName + 13 "‘ that is not fully initialized yet - a consequence of a circular reference"); 14 } 15 else { 16 logger.trace("Returning cached instance of singleton bean ‘" + beanName + "‘"); 17 } 18 } 19 //返回对应的实例,有时候诸如BeanFactory的情况下并不是直接返回实例本身而是返回指定方法返回的实例 20 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 21 } 22 23 else { 24 /** 25 * 只有在单例情况下才会尝试解决循环依赖,原型模式情况下,如果存在A中有B的属性,B中有A的属性, 26 * 那么当依赖注入的时候,就会产生在当A还未创建完成的时候,因为对于B的创建会再次返回创建A,造成循环依赖,也就是下面的情况, 27 * isPrototypeCurrentlyInCreationException(beanName)为true。 28 */ 29 if (isPrototypeCurrentlyInCreation(beanName)) { 30 throw new BeanCurrentlyInCreationException(beanName); 31 } 32 33 //确认是否存在父类工厂 34 BeanFactory parentBeanFactory = getParentBeanFactory(); 35 //若父类不为空并且BeanDefinitionMap中所有加载的类不包括beanName,则尝试在父类工厂去检测 36 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 37 // Not found -> check parent. 38 String nameToLookup = originalBeanName(name); 39 if (parentBeanFactory instanceof AbstractBeanFactory) { 40 return ((AbstractBeanFactory) parentBeanFactory).doGetBean( 41 nameToLookup, requiredType, args, typeCheckOnly); 42 } 43 else if (args != null) { 44 // 委托给具有显示参数args的父工厂 45 return (T) parentBeanFactory.getBean(nameToLookup, args); 46 } 47 else if (requiredType != null) { 48 //委托给标准的父工厂getBean方法 49 return parentBeanFactory.getBean(nameToLookup, requiredType); 50 } 51 else { 52 return (T) parentBeanFactory.getBean(nameToLookup); 53 } 54 } 55 56 if (!typeCheckOnly) { 57 //如果不是仅仅做类型检查则是创建Bean,这里需要进行记录 58 markBeanAsCreated(beanName); 59 } 60 61 try { 62 //将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition,如果指定beanName是子bean的话同时会合并父类的相关属性 63 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 64 checkMergedBeanDefinition(mbd, beanName, args); 65 66 //得到该bean所依赖的相关bean 67 String[] dependsOn = mbd.getDependsOn(); 68 //循环实例化依赖的bean 69 if (dependsOn != null) { 70 for (String dep : dependsOn) { 71 if (isDependent(beanName, dep)) { 72 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 73 "Circular depends-on relationship between ‘" + beanName + "‘ and ‘" + dep + "‘"); 74 } 75 //缓存依赖调用 76 registerDependentBean(dep, beanName); 77 try { 78 getBean(dep); 79 } 80 catch (NoSuchBeanDefinitionException ex) { 81 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 82 "‘" + beanName + "‘ depends on missing bean ‘" + dep + "‘", ex); 83 } 84 } 85 } 86 //到这里已经实例化玩依赖的bean了,所以开始实例化mbd本身了---------------------------- 87 //singleton模式的创建 88 if (mbd.isSingleton()) { 89 sharedInstance = getSingleton(beanName, () -> { 90 try { 91 return createBean(beanName, mbd, args); 92 } 93 catch (BeansException ex) { 94 // Explicitly remove instance from singleton cache: It might have been put there 95 // eagerly by the creation process, to allow for circular reference resolution. 96 // Also remove any beans that received a temporary reference to the bean. 97 destroySingleton(beanName); 98 throw ex; 99 } 100 }); 101 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 102 } 103 104 else if (mbd.isPrototype()) { 105 // prototype模式的创建 106 Object prototypeInstance = null; 107 try { 108 beforePrototypeCreation(beanName); 109 prototypeInstance = createBean(beanName, mbd, args); 110 } 111 finally { 112 afterPrototypeCreation(beanName); 113 } 114 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 115 } 116 117 else { 118 String scopeName = mbd.getScope(); 119 final Scope scope = this.scopes.get(scopeName); 120 if (scope == null) { 121 throw new IllegalStateException("No Scope registered for scope name ‘" + scopeName + "‘"); 122 } 123 try { 124 Object scopedInstance = scope.get(beanName, () -> { 125 beforePrototypeCreation(beanName); 126 try { 127 return createBean(beanName, mbd, args); 128 } 129 finally { 130 afterPrototypeCreation(beanName); 131 } 132 }); 133 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 134 } 135 catch (IllegalStateException ex) { 136 throw new BeanCreationException(beanName, 137 "Scope ‘" + scopeName + "‘ is not active for the current thread; consider " + 138 "defining a scoped proxy for this bean if you intend to refer to it from a singleton", 139 ex); 140 } 141 } 142 } 143 catch (BeansException ex) { 144 cleanupAfterBeanCreationFailure(beanName); 145 throw ex; 146 } 147 } 148 149 // 检查需要的类型是否符合bean的实际类型 150 if (requiredType != null && !requiredType.isInstance(bean)) { 151 try { 152 T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); 153 if (convertedBean == null) { 154 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 155 } 156 return convertedBean; 157 } 158 catch (TypeMismatchException ex) { 159 if (logger.isTraceEnabled()) { 160 logger.trace("Failed to convert bean ‘" + name + "‘ to required type ‘" + 161 ClassUtils.getQualifiedName(requiredType) + "‘", ex); 162 } 163 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 164 } 165 } 166 return (T) bean; 167 }
仅仅从上述代码就能看出来bean的加载经历了一个相当复杂的过程,其中涉及到了各种各样的考虑。对于加载过程中所涉及的步骤大致如下:
(1)转换对应的beanName;
这里需要说明一下转换对应的beanName是什么意思,很多人会认为传入的name不就是beanName吗?其实不是,这里传入的参数可能是别名,也可能是FactoryBean,所以需要进行一系列的解析,这些解析的内容包括如下内容:
? 去除FactoryBean的修饰符,比如说name="&aa",那么首先就会去除&而使得name="aa"。
? 取指定alias所表示的最终beanName,例如别名A指向名称为B的bean则返回B;别名为A指向别名B,别名B又指向名称为C的bean则返回C。
(2)尝试从缓存中加载单例;
单例在Spring的同一个容器内只会被创建一次,后续再获取bean,就直接从单例缓存中获取了。当然这里只是尝试加载,首先创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring中创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时候需要依赖上一个bean则直接使用ObjectFactory。
(3)bean的实例化;
如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。这里需要强调一下,缓存中记录的只是最原始的bean状态,并不一定是我们最终相要的bean。举例说明:假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance()就是完成这个工作的。(后面的文章会详细的讲解)。
(4)原型模式的依赖检查;
只有在单例情况下才会尝试解决循环依赖,如果A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完成的时候因为对B的创建再次返回创建A,造成了循环依赖,也就是这种情况:isPrototypeCurrentlyInCreation(beanName)判断为true。
(5)检测parentBeanFactory;
从代码上看,如果缓存中没有数据的话直接转到父类工厂上去加载,这是为什么呢?
其实不仅仅只是判定缓存中没有数据,这里的判断条件是:parentBeanFactory != null && !containsBeanDefinition(beanName)。parentBeanFactory != null,parentBeanFactory如果为空,则其他一切都是浮云,这就没有什么说的了。但是!containBeanDefinition(beanName)就比较重要了,这句是检测如果当前加载的XML配置文件中不包含beanName所对应的配置,就只能到parentBeanFactory去尝试下了,然后再去递归的调用getBean方法。
(6)将存储XML配置文件的GenericBeanDefinition转换为RootBeanDefinition;
因为从XML配置文件中读取到的bean信息是存储到GenericBeanDefinition上的,但是所有的bean后续处理都是针对RootBeanDefinition的,所以这里需要进行一个转换,转换的同时如果父类bean不为空的话,则合并父类的属性。
(7)寻找依赖;
因为bean的初始化过程很可能会用到某些属性,而某些属性很可能是动态配置的,并且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean,所以,在Spring的加载顺序中,在初始化某一个bean的时候首先会初始化这个bean所对应的依赖。
(8)针对不同的scope进行bean的创建;
在Spring中存在着不同的scope,其中默认的是singleton,但是还有些其他的配置如prototype、request之类的。在这个步骤中,Spring会根据不同的配置进行不同的初始化策略。
(9)类型转换;
程序到这里返回bean后已经基本结束了,通常对该方法的调用参数requiredType是为空的,但是可能会存在这样的情况,返回的bean其实是个String,但是requiredType却传入Integer类型,那么这时候这个步骤就会起作用了,它的功能是将返回的bean转换为requiredType所指定的类型,在Spring中提供了各种各样的转换器,用户也可以自己扩展转换器来满足需求。
经过上面的步骤后,bean的加载就已经结束了,这个时候返回的就是我们需要的bean了。
至此,本篇文章只是大致的对bean加载的流程以及一些特别的点进行说明,接下来的文章会继续围绕着这篇文章进行讲解,使得bean加载过程通透明了。
参考:《Spring源码深度解析》 郝佳 编著:
标签:active ext xpl 状态 current 标准 origin 依赖 返回
原文地址:https://www.cnblogs.com/Joe-Go/p/10140274.html