第三节 Spring加载bean的过程
前言
通过前面两节的学习我们已经知道了Spring
是如何解析XML
与装载BeanDefinition
的;在本章节中我们将继续学习bean
的装载过程这将会面临更大的挑战,bean加载的功能实现远比bean的解析要复杂得多,不过没关系,步步深入层层解析终将会有收获。我们还是以一个例子开始:
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("application.xml"));
User user = (User)beanFactory.getBean("user");
bean的加载
我们在idea中跟踪getBean("user")
进一步探秘,最后来到了我们想看到的AbstractBeanFactory#doGetBean()
;所以今天的内容将从此开始,我们先贴出该方法的主要代码:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {// 1.提取对应的 beanNamefinal String beanName = transformedBeanName(name);Object bean;/* **检査缓存中或者实例工厂中是否有对应的实例*为什么首先会使用这段代码呢,*因为在创建单例 bean 的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环 依赖,* Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提早曝光*也就是将 ObjectFactory 加入到缓存中,一旦下个 bean 创建时候需要依赖上个 bean 则直接使用 ObjectFactory*/// 2.直接尝试从缓存获取或者 singletonFactories 中的 ObjectFactory 中获取Object sharedInstance = getSingleton(beanName);if (sharedInstance != null && args == null) {if (logger.isDebugEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.debug(".....");} else {logger.debug(".....");}}// 3.返回对应的实例,有时候存在诸如 BeanFactory 的情况并不是直接返回实例本身而是返回指定方法返回的实例 beanbean = getObjectForBeanInstance(sharedInstance, name, beanName, null);} else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.// 指定的bean是否正在创建中if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 检查该工厂中是否存在bean定义// Check if bean definition exists in this factory.BeanFactory parentBeanFactory = getParentBeanFactory();// //如果 beanDefinitionMap 中也就是在所有已经加载的类中不包括 beanName 则尝试从if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.//parentBeanFactory 中检测String nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);} else if (args != null) {// Delegation to parent with explicit args. 使用显式参数委派给父级return (T) parentBeanFactory.getBean(nameToLookup, args);} else {// No args -> delegate to standard getBean method.return parentBeanFactory.getBean(nameToLookup, requiredType);}}// 如果不是仅仅做类型检查则是创建 bean,这里要进行记录if (!typeCheckOnly) {markBeanAsCreated(beanName);}try {// 4.将存储 XML 配置文件的 GernericBeanDefinition 转换为 RootBeanDefinitionfinal RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);// 如果指定BeanName 是子 Bean 的话同时会合并父类 的相关属性checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.String[] dependsOn = mbd.getDependsOn();// 若的 存在依赖则需要递归实例化依赖的 beanif (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"......'");}//缓存依赖调用registerDependentBean(dep, beanName);try {getBean(dep);} catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"......", ex);}}}// Create bean instance.// 5.实例化依赖的 bean 后便可以实例化 mbdif (mbd.isSingleton()) {// 单例模式的创建sharedInstance = getSingleton(beanName, () -> {try {// 创建beanreturn createBean(beanName, mbd, args);} catch (BeansException ex) {destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);// 创建 多例的bean} else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.Object prototypeInstance = null;try {beforePrototypeCreation(beanName);prototypeInstance = createBean(beanName, mbd, args);} finally {afterPrototypeCreation(beanName);}bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);} else {String scopeName = mbd.getScope();// 指定的 scope 上实例化beanfinal Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("......");}try {Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);} finally {afterPrototypeCreation(beanName);}});bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);} catch (IllegalStateException ex) {throw new BeanCreationException(beanName,"......",ex);}}} catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// // 检査需要的类型是否符合 bean// Check if required type matches the type of the actual bean instance.if (requiredType != null && !requiredType.isInstance(bean)) {try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return convertedBean;} catch (TypeMismatchException ex) {if (logger.isDebugEnabled()) {logger.debug("......", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;}
我们来总结一下这一段代码都干了什么;
- 转换对应
beanName
或许很多人不理解转换对应beanName是什么意思,传入的参数name不就是beanName 吗?其实不是,这里传入的参数可能是别名,也可能是FactoryBean,所以需要进行一系列的 解析,这些解析内容包括如下内容。
去除FactoryBean的修饰符,也就是如果name="&aa"
那么会首先去除&
而使name="aa"
取指定alias
所表示的最终beanName,例如别名A指向名称为B的bean则返回B; 若别名A指向别名B,别名B又指向名称为C的bean则返回C。
尝试从缓存中加载单例
单例在Spring的同一个容器内只会被创建一次,后续再获取bean,就直接从单例缓存中获 取了。当然这里也只是尝试加载,首先尝试从缓存中加载,如果加载不成功则再次尝试从singletonFactories
中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖 的时候为了避免循环依赖,在Spring中创建bean的原则是不等bean创建完成就会将创建bean 的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时候需要依赖上一个bean则直 接使用ObjectFactory (后面章节会对循环依赖重点讲解)。bean的实例化
如果从缓存中得到了 bean的原始状态,则需要对bean进行实例化。这里有必要强调一下, 缓存中记录的只是最原始的bean状态,并不一定是我们最终想要的bean。举个例子,假如我 们需要对工厂bean进行处理,那么这里得到的其实是工厂bean的初始状态,但是我们真正需 要的是工厂bean中定义的factory-method
方法中返回的bean,而getObjectForBeanlnstance
就 是完成这个工作的,后续会详细讲解。原型模式的依赖检查
只有在单例情况下才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性, 那么当依赖注入的时候,就会产生当A还未创建完的时候因为对于B的创建再次返回创建A, 造成循环依赖,也就是情况:isPrototypeCurrentlylnCreation(beanName)判断 true
。
- 检测parentBeanFactory
从代码上看,如果缓存没有数据的话直接转到父类工厂上去加载了,这是为什么呢?
可能读者忽略了一个币要的判断条件:parentBeanFactory!=null&&IcontainsBean Definition (beanName), parentBeanFactory != null parentBeanFactory如果为空,则其他一切都是浮云, 这个没什么说的,但是!containsBeanDefinition(beanName)就比较重要了,它是在检测如果当前 加载的XML配置文件中不包含beanName所对应的配置,就只能到parentBeanFactory去尝试然后再去递归的调用getBean方法。
- 将存储
XML
配置文件的GernericBeanDefinition
转换为RootBeanDefinition
因为从XML配置文件中读取到的bean信息是存储在GernericBeanDefinition
中的,但是所 有的bean后续处理都是针对于RootBeanDefinition
的,所以这里需要进行一个转换,转换的同时 如果父类bean不为空的话,则会一并合并父类的属性。
- 寻找依赖
因为bean的初始化过程中很可能会用到某些属性,而某些属性很可能是动态配置的,并 且配置成依赖于其他的bean,那么这个时候就有必要先加载依赖的bean,所以,在Spring的 加载顺寻中,在初始化某一个bean的时候首先会初始化这个bean所对应的依赖。
- 针对不同的scope进行bean的创建
我们都知道,在Spring中存在着不同的scope,其中默认的是singleton,但是还有些其他 的配置诸如prototype、request之类的。在这个步骤中,Spring会根据不同的配置进行不同的初 始化策略。
- 类型转换
程序到这里返回bean后已经基本结束了,通常对该方法的调用参数requiredType是为空的, 但是可能会存在这样的情况,返回的bean其实是个String,但是requiredType却传入Integer 类型,那么这时候本步骤就会起作用了,它的功能是将返回的bean转换为requiredType所指定 的类型。当然,String转换为Integer是最简单的一种转换,在Spring中提供了各种各样的转换 器,用户也可以自己扩展转换器来满足需求。
经过上面的步骤后bean的加载就结束了,这个时候就可以返回我们所需要的bean 了;接下来我们具体分析一下代码中的一些核心步骤,请大家留意上述代码中注释的编号顺序
:
流程分析
大概熟悉了这个方法所起的作用之后,我们具体分析一下一些核心步骤所做的事情,按照上述代码中注释的编号顺序,继续往下看:
提取对应的 beanName
transformedBeanName(name)
方法主要是确定原始名称,将别名解析为规范名称。比如将factorybean类型的beanname的前缀&
替换掉。缓存中获取单例bean
跟踪
getSingleton(beanName)
方法我们来到DefaultSingletonBeanRegistry
类中,代码如下:protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 当某些方法需要提前初始化的时候则会调用 addSingletonFactory 方法将对应的//ObjectFactory 初始化策略存储在 singletonFactoriessingletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {//调用预先设定的 get Object 方法 singletonObject = singletonFactory.getObject();singletonObject = singletonFactory.getObject();//记录在缓存中,earlySingletonObjects 和 singletonFactories 互斥this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}
从方法名就可以知道这是获取单例的bean,单例在Spring的同一个容器内只会被创建一次,后续再获取bean直接从单例缓存中获取,当然 这里也只是尝试加载,首先尝试从缓存中加载,然后再次尝试尝试从singletonFactories中加载。 因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖, Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光加入到 缓存中,一旦下一个bean创建时需要依赖上个bean,则直接使用ObjectFactory。
这个方法首先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingletonObjects 里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的 ObjectFactory,然后调用这个 ObjectFactory 的 getObject 来创建 bean,并放到 earlySingletonObjects 里面去,并且从singletonFacotories里面remove掉这个ObjectFactory,而对于后续的所 有内存操作都只为了循环依赖检测时候使用,也就是在allowEarlyReference为true的情况下才 会使用,而它默认就是true。
这里涉及用于存储bean的不同的map简单解释如下。- singletonObjects:用于保存 BeanName 和创建 bean 实例之间的关系,bean name —> beaninstance
- singletonFactories:用于保存BeanName和创建bean的工厂之间的关系,bean name ~> ObjectFactory
- earlySingletonObjects:也是保存BeanName和创建bean实例之间的关系,与 singletonObjects的不同之处在于,当一个单例bean被放到这里面后,那么当bean还 在创建过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用。
- registeredSingletons:用来保存当前所有已注册的bean。
从bean的实例中获取对象
跟踪
getObjectForBeanInstance()
方法,我们来到AbstractBeanFactory
类中,代码如下:protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {// bean name是不是以 & 开头if (BeanFactoryUtils.isFactoryDereference(name)) {if (beanInstance instanceof NullBean) {return beanInstance;}if (!(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());}}// 现在我们有了个 bean 的实例,这个实例可能会是正常的 bean 或者是 FactoryBean// 如果是 FactoryBean 我们使用它创建实例,但是如果用户想要直接获取工厂实例而不是工厂的// getObject 方法对应的实例那么传入的 name 应该加入前缀if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {return beanInstance;}Object object = null;if (mbd == null) {// 尝试从缓存中加载 beanobject = getCachedObjectForFactoryBean(beanName);}if (object == null) {// Return bean instance from factory.// 到这里已经明确知道 beaninstance 一定是 FactoryBean 类型FactoryBean<?> factory = (FactoryBean<?>) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.//containsBeanDefinition 检测 beanDefinitionMap 中也就是在所有已经加载的类中检测 是否定义 beanNameif (mbd == null && containsBeanDefinition(beanName)) {//将存储 XML 配置文件的 GernericBeanDefinition 转换为 RootBeanDefinition,如果指定 BeanName 是子 Bean 的话同时会合并父类的相关属性mbd = getMergedLocalBeanDefinition(beanName);}//是否是用户定义的而不是应用程序本身定义的boolean synthetic = (mbd != null && mbd.isSynthetic());object = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;}
这个方法中主要确定了bean的类型是不是
FactoryBean
如果是,又委托给getObjectFromFactoryBean(factory, beanName, !synthetic)
方法,继续深入。进入FactoryBeanRegistrySupport
类中:protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {if (factory.isSingleton() && containsSingleton(beanName)) {synchronized (getSingletonMutex()) {Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {// 划重点object = doGetObjectFromFactoryBean(factory, beanName);// Only post-process and store if not put there already during getObject() call above// (e.g. because of circular reference processing triggered by custom getBean calls)Object alreadyThere = this.factoryBeanObjectCache.get(beanName);if (alreadyThere != null) {object = alreadyThere;} else {if (shouldPostProcess) {if (isSingletonCurrentlyInCreation(beanName)) {// Temporarily return non-post-processed object, not storing it yet..return object;}// 正在创建的bean放到缓存中beforeSingletonCreation(beanName);try {//Spring获取bean的规则中有这样一条 :尽可能保证所有 bean 初始化后都会调用注册的 的 BeanPostProcessor的 postProcessAfterlnitialization 方法进行处理object = postProcessObjectFromFactoryBean(object, beanName);} catch (Throwable ex) {throw new BeanCreationException(beanName,"Post-processing of FactoryBean's singleton object failed", ex);} finally {//正在创建的bean从缓存中移除afterSingletonCreation(beanName);}}if (containsSingleton(beanName)) {this.factoryBeanObjectCache.put(beanName, object);}}}return object;}} else {Object object = doGetObjectFromFactoryBean(factory, beanName);if (shouldPostProcess) {try {object = postProcessObjectFromFactoryBean(object, beanName);} catch (Throwable ex) {throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);}}return object;}}
在这个方法中我们还没有看到想看的代码不过没关系,细心的你早已发现这里面包含两个重要的方法;
Object object = doGetObjectFromFactoryBean(factory, beanName);
以及object = postProcessObjectFromFactoryBean(object, beanName);
第一个很明显就是委托获取bean的实现,第二个是bean的后置处理器;后续章节重点分析。private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)throws BeanCreationException {Object object;try {if (System.getSecurityManager() != null) {AccessControlContext acc = getAccessControlContext();try {object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);} catch (PrivilegedActionException pae) {throw pae.getException();}} else {// 划重点object = factory.getObject();}} catch (FactoryBeanNotInitializedException ex) {throw new BeanCurrentlyInCreationException(beanName, ex.toString());} catch (Throwable ex) {throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);}......省略}return object;}
终于我们看到了,
object = factory.getObject();
经过一番波折我们知道了factoryBean
的bean最终的获取的对象就是调用它本身的getObject()
实现的。Definition的转换
//将存储 XML 配置文件的 GernericBeanDefinition 转换为 RootBeanDefinitionfinal RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); --------------------------- protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {// Quick check on the concurrent map first, with minimal locking.RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);if (mbd != null) {return mbd;}// beanDefinitionMap 中获取 beandefination 返回 RootBeanDefinitionreturn getMergedBeanDefinition(beanName, getBeanDefinition(beanName));} -------------------------- public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {// 重点BeanDefinition bd = this.beanDefinitionMap.get(beanName);if (bd == null) {if (this.logger.isTraceEnabled()) {this.logger.trace("No bean named '" + beanName + "' found in " + this);}throw new NoSuchBeanDefinitionException(beanName);}return bd;}
在这部分代码中主要是将
GernericBeanDefinition
转换为RootBeanDefinition
;在第二节解析xml装配BeanDefinition
的时候我们就知道了最初的bean就是GernericBeanDefinition
类型的。而beanDefinitionMap
中的BeanDefinition
也是在第二节所说到的,解析好的BeanDefinition
所注册的map对象;这也正好前后一一印证了。实例化依赖的 bean
// 单例模式的创建 sharedInstance = getSingleton(beanName, () -> {try {// 创建beanreturn createBean(beanName, mbd, args);} catch (BeansException ex) {destroySingleton(beanName);throw ex;} });
之前我们讲解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例bean 就需要从头开始bean的加载过程了,而Spring中使用
getSingleton
的重载方法实现bean的加 载过程,进一步深入DefaultSingletonBeanRegistry
类中:public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {//首先检査对应的 bean 是否已经加载过,因为 singleton 模式其实就是复用以创建的 bean,Object singletonObject = this.singletonObjects.get(beanName);//如果为空.则锁定全局变量并进行处理if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"......");}if (logger.isDebugEnabled()) {logger.debug("......");}// 正在创建的bean 放到缓存中beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}// 正在创建的bean从缓存中移除afterSingletonCreation(beanName);}if (newSingleton) {// 将结果记录至缓存并删除加载 bean 过程中所记录的各种辅助状态addSingleton(beanName, singletonObject);}}return singletonObject;}}
上述代码中其实是使用了回调方法,使得程序可以在单例创建的前后做一些准备及处理操 作,而真正的获取单例bean的方法其实并不是在此方法中实现的,其实现逻辑是在
ObectFactoty
类型的实例singletonFactory
中实现的,我们也能在代码中看到返回的对象也正是调用singletonFactory.getObject()
返回的。而这些准备及处理操作包括如下内容。- 检查缓存是否已经加载过。
- 若没有加载,则记录beanName的正在加载状态。
- 加载单例前记录加载状态。
我们返回去看一下
singletonFactory
对象的创建过程createBean(beanName, mbd, args)
,进入AbstractAutowireCapableBeanFactory
类,代码如下:protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isDebugEnabled()) {logger.debug("......");}RootBeanDefinition mbdToUse = mbd;/*** 确保此时确实解析了bean类,如果动态解析的类无法存储在共享的合并bean定义中。*/ which cannot be stored in the shared merged bean definition.Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.准备方法替代 对override属性进行标记及验证try {mbdToUse.prepareMethodOverrides();} catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// 给BeanPostProcessors一个返回代理而不是目标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);}try {// 开始创建beanObject beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isDebugEnabled()) {logger.debug("Finished creating instance of bean '" + beanName + "'");}return beanInstance;} catch (...) {......}}
从代码中我们可以总结出函数完成的具体步骤及功能。
- 根据设置的class属性或者根据className来解析Class。
- 对override属性进行标记及验证。
- 应用初始化前的后处理器,解析指定bean是否存在初始化前的短路操作。
创建bean的过程又委托给 doCreateBean(beanName, mbdToUse, args);
去实现,那么接下来我们老规矩,继续深入 AbstractAutowireCapableBeanFactory
类中:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {//根据指定 bean 使用对应的策略创建新的实例,如:工厂方法、构造函数自动注入、简单初始化 instancewrapperinstanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}synchronized (mbd.postProcessingLock) {if (!mbd.postProcessed) {try {// bean的后置处理器applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);} catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"......", ex);}mbd.postProcessed = true;}}// 是否需要提早曝光: 单例& 允许循环依赖& 当前 beanboolean 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");}// 为避免后期循环依赖,可以在 bean 初始化完成前将创建实例的 Object Factory 加入工厂addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {// 对 bean 进行填充 , 将各个属性值注入其中,他可能存在依赖于其他bean的属性 ,则会递归初始populateBean(beanName, mbd, instanceWrapper);// 调用初始化方法,比如 init-methodexposedObject = 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);// earlySingletonReference只有在检测到有循环依赖的情况下才会不为空if (earlySingletonReference != null) {// 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强if (exposedObject == bean) {exposedObject = earlySingletonReference;} else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);for (String dependentBean : dependentBeans) {// 检测依赖if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {actualDependentBeans.add(dependentBean);}}/*** 因为 bean 创建后其所依赖的 bean —定是已经创建的,* actualDependentBeans 不为空则表示当前前 bean 创建后其依赖的的 bean 却没有没全部创建完,也就是说存在循环依赖*/if (!actualDependentBeans.isEmpty()) {throw new BeanCurrentlyInCreationException(beanName,"Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +".......");}}}}// Register bean as disposable.try {// 根据 scopse 注册 beanregisterDisposableBeanIfNecessary(beanName, bean, mbd);} catch (BeanDefinitionValidationException ex) {throw ......;}return exposedObject;}
我们来看一下这个方法的整体思路:
- 如果是单例则需要首先清除缓存。
- 实例化 bean,将 BeanDefinition 转换为 Bean Wrapper。转换是一个复杂的过程,但是我们可以尝试概括大致的功能,如下所示。
- 如果存在工厂方法则使用工厂方法进行初始化。
- 一个类有多个构造函数,每个构造函数都有不同的参数,所以需要根据参数锁定构造 函数并进行初始化。
- 如果既不存在工厂方法也不存在带有参数的构造函数,则使用默认的构造函数进行 bean的实例化。
- MergedBeanDefinitionPostProcessor 的应用。
bean合并后的处理,Autowired注解正是通过此方法实现诸如类型的预解析。 - 依赖处理。
在Spring中会有循环依赖的情况,例如,当A中含有B的属性,而B中又含有A的属性 时就会构成一个循环依赖,此时如果A和B都是单例,那么在Spring中的处理方式就是当创 建B的时候,涉及自动注入A的步骤时,并不是直接去再次创建A,而是通过放入缓存中的 ObjectFactory来创建实例,这样就解决了循环依赖的问题 - 属性填充。将所有属性填充至bean的实例中。
- 循环依赖检査。
之前有提到过,在Sping中解决循环依赖只对单例有效,而对于prototype的bean, Spring 没有好的解决办法,唯一要做的就是抛出异常。在这个步骤里面会检测已经加载的bean是否 已经出现了依赖循环,并判断是否需要抛出异常。 - 注册 DisposableBeano
如果配置了 destroy-method,这里需要注册以便于在销毁时候调用。 - 完成创建并返回。
可以看到上面的步骤非常的繁琐,每一步骤都使用了大量的代码来完成其功能,最复杂 也是最难以理解的当属循环依赖的处理,在真正进入doCreateBean前我们有必要先了解下循 环依赖。
6.创建bean的实例
首先我们从 createBeanlnstance
开始:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// Make sure bean class is actually resolved at this point.Class<?> beanClass = resolveBeanClass(mbd, beanName);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());}Supplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}// 如果工厂方法不为空则使用工厂方法初始化策略if (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}if (resolved) {if (autowireNecessary) {// 构造函数return autowireConstructor(beanName, mbd, null, null);} else {// 默认的构造函数return instantiateBean(beanName, mbd);}}// 根据参数解析构造函数Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {// 构造函数自动驻入return autowireConstructor(beanName, mbd, ctors, args);}// 根据不同的实例化策略进行实例化return instantiateBean(beanName, mbd);}
虽然代码中实例化的细节非常复杂,但是在createBeanlntance方法中我们还是可以清晰地 看到实例化的逻辑的。
- 如果在RootBeanDefinition中存在factoryMethodName属性,或者说在配置文件中配置 了 factory-method,那么 Spring 会尝试使用 instantiateUsingFactoiyMethod(beanName, mbd, aigs)方法
- 解析构造函数并进行构造函数的实例化。因为一个bean对应的类中可能会有多个构造 函数,而每个构造函数的参数不同,Spring在根据参数及类型去判断最终会使用哪个构造函数 进行实例化。但是,判断的过程是个比较消耗性能的步骤,所以釆用缓存机制,如果已经解析过则 不需要重复解析而是直接从RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod缓存 的值去取,否则需要再次解析,并将解析的结果添加至RootBeanDefinition中的属性 resolvedConstructorOrFactoryMethod 中。
我们发现创建 BeanWrapper
的任务又委托给 instantiateBean(beanName, mbd);
来处理,老规矩继续深入 AbstractAutowireCapableBeanFactory
类中:
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {try {Object beanInstance;final BeanFactory parent = this;if (System.getSecurityManager() != null) {beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->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);}}
依然没有看到我们想看到的类容,继续深入 SimpleInstantiationStrategy
类中:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {// Don't override the class with CGLIB if no overrides.// 如果有需要覆盖或者动态替换的方法则当然需要使用 cglib 进行动态代理,因为可以在创建代理的同时将动态方法织入类中// 但是如果没有需要动态改变得方法,为了方便直接反射就可以了if (!bd.hasMethodOverrides()) {Constructor<?> constructorToUse;synchronized (bd.constructorArgumentLock) {constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;if (constructorToUse == null) {final Class<?> clazz = bd.getBeanClass();if (clazz.isInterface()) {throw new BeanInstantiationException(clazz, "Specified class is an interface");}try {if (System.getSecurityManager() != null) {constructorToUse = AccessController.doPrivileged((PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);}else {constructorToUse = clazz.getDeclaredConstructor();}bd.resolvedConstructorOrFactoryMethod = constructorToUse;}catch (Throwable ex) {throw new BeanInstantiationException(clazz, "No default constructor found", ex);}}}return BeanUtils.instantiateClass(constructorToUse);}else {// Must generate CGLIB subclass. 必须生成CGLIB子类。return instantiateWithMethodInjection(bd, beanName, owner);}}
程序中,首先判断如果beanDefinitioikgetMethodOverrides
为空也就是 用户没有使用replace或者lookup的配置方法,那么直接使用反射的方式,简单快捷,但是如果使 用了这两个特性,在直接使用反射的方式创建实例就不妥了,因为需要将这两个配置提供的功能切进去,所以就必须要使用动态代理的方式将包含两个特性所对应的逻辑的拦截增强器设置进去, 这样才可以保证在调用方法的时候会被相应的拦截器增强,返回值为包含拦截器的代理实例。至此一个完整的 BeanWrapper
就转配完了;接下来返回 AbstractAutowireCapableBeanFactory
类的 doCreateBean()
方法中,继续完成下面的类容:
// Initialize the bean instance.Object exposedObject = bean;try {// 对 bean 进行填充 , 将各个属性值注入其中,他可能存在依赖于其他bean的属性 ,则会递归初始populateBean(beanName, mbd, instanceWrapper);// 调用初始化方法,比如 init-methodexposedObject = 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);}}
在 populateBean(beanName, mbd, instanceWrapper);
完成了对属性的填充,二而initializeBean(beanName, exposedObject, mbd);
的作用就显而易见了:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());} else {// bean是否有aware接口的实现invokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 调前置处理器wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 执行init方法 自定义的 bean 实 实 现 现 InitializingBean 口 接口invokeInitMethods(beanName, wrappedBean, mbd);} catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {// 调后置处理器wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}
虽然说此函数的主要目的是进行客户设定的初始化方法的调用,但是除此之外还有些其他 必要的工作。
- 激活Aware方法
在分析其 前,我们先了解一下Aware的邮 Spring中些Aware相趣口,比如
BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware x ServletContextAware 等,实 些Aware接口的bean在被初始之后,可以取得一些相对应的资源,例如实现BeanFactoryAware的bean 在初始后,Spring容器将会注入BeanFactory的实例,而实现ApplicationContextAware的bean,在 bean被初始后,将会被注入Applicationcontext的实例等。 - 处理器的应用
BeanPostProcessor相信大家都不陌生,这是Spring中开放式架构中一个必不可少的亮点, 给用户充足的权限去更改或者扩展Spring,而除了 BeanPostProcessor外还有很多其他的 PostProcessor,当然大部分都是以此为基础,继承自 BeanPostProcessor。BeanPostProcessor 的 使用位置就是这里,在调用客户自定义初始化方法前以及调用自定义初始化方法后分别会调用 BeanPostProcessor 的 postProcessBefbrelnitialization 和 postProcessAfterlnitialization 方法,使用 户可以根据自己的业务需求进行响应的处理。 - 激活自定义的init方法
客户定制的初始化方法除了我们熟知的使用配置init-method夕卜,还有使自定义的bean实 现InitializingBean接口 ,并在afterPropertiesSet中实现自己的初始化业务逻辑。
至此createBean(beanName, mbd, args);
方法中的所有核心步骤都完了。回到AbstractBeanFactory
中我们发现同开始我们曾分析的方法一样又调用一次·bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
不再阐述。最后一个完整的bean已经初始华完毕了。
后语
Spring的加载bean的流程是复杂而又庞大的,我们的分析相对简陋但是也包含了几乎所有的核心流程,日积月累中将会有收获。下一章节我们将继续分析spring容器的功能扩展
。
第三节 Spring加载bean的过程相关推荐
- java spring 加载bean,Spring多种加载Bean方式解析
1 定义bean的方式 常见的定义Bean的方式有: 通过xml的方式,例如: ? 通过注解的方式,在Class上使用@Component等注解,例如 ? 通过在@Configuration类下的@B ...
- Spring 加载Bean流程
2019独角兽企业重金招聘Python工程师标准>>> loadBeanDefinitions 加载类的定义信息 public int loadBeanDefinitions(Enc ...
- Spring加载流程源码
一.从AbstractApplicationContext的体系说起 第一,从类结构设计上看, 围绕着是否需要Refresh容器衍生出两个抽象类: GenericApplicationContext: ...
- Spring IOC 之 加载 Bean
2019独角兽企业重金招聘Python工程师标准>>> 这段代码是 Spring 中编程式使用 IOC 容器,通过这四段简单的代码,我们可以初步判断 IOC 容器的使用过程 获取资源 ...
- spring之:XmlWebApplicationContext作为Spring Web应用的IoC容器,实例化和加载Bean的过程...
它既是 DispatcherServlet 的 (WebApplicationContext)默认策略,又是 ContextLoaderListener 创建 root WebApplicationC ...
- 【死磕 Spring】----- IOC 之 加载 Bean
原文:https://www.cmsblogs.com/category/1391374860344758272 『chenssy』 先看一段熟悉的代码: ClassPathResource reso ...
- Spring 加载、解析applicationContext.xml 流程
概要 Spring 框架使用了BeanFactory 进行加载 xml 和生成 bean 实例.下面我们分析下Spring加载xml文件的过程. spring 版本是最新的 4.3.9 release ...
- Spring生命周期Bean初始化过程详解
Spring生命周期Bean初始化过程详解 Spring 容器初始化 Spring Bean初始化 BeanFactory和FactoryBean 源码分析 Bean的实例化 preInstantia ...
- Spring加载properties文件的两种方式
2019独角兽企业重金招聘Python工程师标准>>> 在项目中如果有些参数经常需要修改,或者后期可能需要修改,那我们最好把这些参数放到properties文件中,源代码中读取pro ...
最新文章
- Matlab编程与数据类型 -- 出错处理语句try/catch/end
- [转载]html5教程
- 【原创】packetbeat 之“request-response 错误关联”问题
- 一步步教你前端vue项目开发中如何解决跨域问题
- 贷款利润最大化——利用随机森林和逻辑回归
- 2021年度公有云安全报告
- ubuntu16.04安装gradle
- jdk1.8新特性的应用-Stream 的终止操作
- 我有你没有游戏例子100_50米的决赛圈里面藏着100个人?光子:知道什么叫质量局了吧!...
- Java线程同步之一--AQS
- 江湖小白之一起学Python (三)双色球历史数据抓取
- 读书笔记——晶体管电路设计
- Android 智能手机程序使用历史记录查询
- python输入城市找省份_利用字典模拟省市区(县)的查询
- apex显示服务器连接超时,apex与服务器链接超时
- 面向金融场景的 Vue.js 移动端组件库 mand-mobile
- 几万年前,有一只猴子大闹地府后删库跑路
- unity网络资源导入
- mysql删除重复记录语句
- Hank Paulson Is A National Hero
热门文章
- 诡异的sqlite3之malformed错误(一)
- pl/sql developer 7.1 出来一段时间了,郁闷是与万能五笔冲突
- 微信删除的图片怎么恢复?微信照片过期或已被清理如何还原
- 今天遇到res\layout\activity_easy_bid.xml.r8010:0: error: Resource entry activ
- freemarker 标签的一些用法
- 计算机毕业设计Java薪酬福利管理信息系统(源码+系统+mysql数据库+lw文档
- 有关access的上机试题_计算机Access考试上机试题
- 【HDU 1059】Dividing(多重背包)
- Spring 全家桶BeanDefinition资源定位解析-立哥技术
- 在此计算机中找不到cad,在此计算机上找不到AutoCAD201x,你需要安装AutoCAD201x才可以安装此语言包CAD安装失败解决方法...