创建bean
前言
上一篇文章讲述了循环依赖以及Spring中的循环依赖的处理方式后,我们接着准备创建bean这篇文章来继续讲述bean的创建,先回顾一下(截取部分createBean代码):
try { // 给BeanPostProcessors一个机会来返回代理来替代真正的实例 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 { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'"); } return beanInstance; }
可以看出在经历过resolveBeforeInstantiation方法后,上述代码有两个返回途径,如果创建了代理或者说重写了InstantiationAwareBeanPostProcessor类的postProcessBeforeInstantiation方法并在方法postProcessBeforeInstantiation中改变了bean,则直接返回,否则的话就需要进行常规的bean创建。而这种常规的bean创建是在doCreateBean()方法中完成的。
创建bean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException { // 实例化bean BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { //如果是单例的话,移除缓存中的bean instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //根据指定的bean使用对应的策略创建新的实例,如:工厂方法,构造函数自动注入,简单初始化 instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { //bean合并后处理 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed", ex); } mbd.postProcessed = true; } } //是否需要提早曝光:单例 && 允许循环依赖 && 当前bean正在创建中,判断是否有循环依赖 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //为了避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { //对bean进行填充,将各个属性注入,其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean populateBean(beanName, mbd, instanceWrapper); //调用初始化方法,比如init-method exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); //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); } } 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."); } } } } // Register bean as disposable. try { //根据scope注册bean registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
日志和异常的内容非常重要,但是在阅读源码的时候大部分的人都会直接忽略掉。在这里不探讨日志和异常,我们来看看函数的思路概要(配合注释其实已经大部分能看懂,先大致了解流程步骤,后面我们在一步一步详细了解):
(1)如果是单例则需要首先清除缓存;
(2)实例化bean,将BeanDefinition转换为BeanWrapper;
转换是一个复杂的过程,大致的功能有:
❤ 如果存在工厂方法则使用工厂方法进行初始化;
❤ 一个类有多个构造函数,每个构造函数有不同的参数,所以需要根据参数锁定构造函数并进行初始化;
❤ 如果即不存在工厂方法也不存在带有参数的构造函数,则使用默认的构造函数进行bean的实例化;
(3)bean的合并后处理;
bean的合并后处理,Autowire注解正是通过这个方法实现诸如类型的预解析;
(4)依赖处理;
在Spring中会有循环依赖的情况,例如:当A中含有B的属性,而B中又含有A的属性就会构成一个循环依赖,此时如果A和B都是单例,那么在Spring中的处理方式就是当创建B的时候,涉及到注入A的操作时,并不是直接去再次创建A,而是通过放入缓存中的ObjectFactory来创建实例,这样就解决了循环依赖的问题;
(5)属性填充,将所有的属性填充至bean的实例中;
(6)循环依赖检查;
上一篇文章讲述了,在Spring中解决循环依赖只是对单例有效,而对于property的bean,Spring没有好的解决办法,唯一做的就是抛出异常。在这个步骤里面会检测加载的bean是否出现了循环依赖,并判断是否抛出异常;
(7)注册DisposableBean;
如果配置了destroy-method,这里需要注册以便于在销毁时调用;
(8)完成创建并返回。
可以看出上述的步骤非常的繁琐,每一步都使用了大量的代码来完成其涉及的功能,最复杂也是最难理解的当属循环依赖的处理。下面我们就一步一步详细的了解创建bean的每个步骤。
1 创建bean的实例
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 解析class 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); } // Shortcut when re-creating the same bean... 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() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // 构造函数自动注入 ctors = mbd.getPreferredConstructors(); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, null); } // 默认构造函数构造 return instantiateBean(beanName, mbd); }
配合注释我们可以清晰的看出实例化的逻辑:
(1)如果在RootBeanDefinition中存在factoryMethodName属性,或者说在配置文件中配置了factory-method,那么Spring会尝试使用InstantiateUsingFactoryMethod(beanName,mbd,args)方法根据RootBeanDefinition中的配置生成bean的实例。
(2)解析构造函数并进行构造函数的实例化。因为一个bean对应的类中可能会有多个构造函数,而每个构造函数的参数不同,Spring根据参数以及类型去判断最终会使用到哪个构造函数进行实例化。但是,判断的过程是个比较耗费性能的操作,所以采用了缓存机制,如果已经解析过,则不需要重复解析而是直接从RootBeanDefinition中的属性resolvedConstrutorOrFactoryMethod缓存的值去取,否则需要再次解析,并将解析的结果添加至RootBeanDefinition中的属性resolvedConstructorOrFactoryMethod中。
接下来,对createBeanInstance方法中的重点方法进行解析:
1.autowiredConstructor
对于实例的创建Spring中分成了两种情况,一种是通用的实例化,另一种是带有参数的实例化。带有参数的实例化过程相当复杂,因为存在着不确定性,所以在判断对应参数上做了大量的工作:
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) { BeanWrapperImpl bw = new BeanWrapperImpl(); this.beanFactory.initBeanWrapper(bw); Constructor<?> constructorToUse = null; ArgumentsHolder argsHolderToUse = null; Object[] argsToUse = null; //exolicitArgs通过getBean传入,如果getBean方法调用的时候指定方法参数那么直接使用 if (explicitArgs != null) { argsToUse = explicitArgs; } else { //如果在getBean方法的时候没有指定则尝试从配置文件中解析 Object[] argsToResolve = null; //尝试从缓存中获取 synchronized (mbd.constructorArgumentLock) { constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod; if (constructorToUse != null && mbd.constructorArgumentsResolved) { // 从缓存中去取 argsToUse = mbd.resolvedConstructorArguments; if (argsToUse == null) { //配置构造函数参数 argsToResolve = mbd.preparedConstructorArguments; } } } //如果缓存中存在 if (argsToResolve != null) { //解析参数类型,如给定方法的构造函数A(int,int)则通过此方法后就会把配置中的("1","1")转换为(1,1) argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true); } } //没有被缓存 if (constructorToUse == null || argsToUse == null) { // Take specified constructors, if any. Constructor<?>[] candidates = chosenCtors; if (candidates == null) { Class<?> beanClass = mbd.getBeanClass(); try { candidates = (mbd.isNonPublicAccessAllowed() ? beanClass.getDeclaredConstructors() : beanClass.getConstructors()); } catch (Throwable ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Resolution of declared constructors on bean Class [" + beanClass.getName() + "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex); } } if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) { Constructor<?> uniqueCandidate = candidates[0]; if (uniqueCandidate.getParameterCount() == 0) { synchronized (mbd.constructorArgumentLock) { mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate; mbd.constructorArgumentsResolved = true; mbd.resolvedConstructorArguments = EMPTY_ARGS; } bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS)); return bw; } } // Need to resolve the constructor. boolean autowiring = (chosenCtors != null || mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR); ConstructorArgumentValues resolvedValues = null; int minNrOfArgs; if (explicitArgs != null) { minNrOfArgs = explicitArgs.length; } else { //提取配置文件中的配置的构造函数参数 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); //用于承载解析后的构造函数参数的值 resolvedValues = new ConstructorArgumentValues(); //能解析到的参数个数 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); } AutowireUtils.sortConstructors(candidates); int minTypeDiffWeight = Integer.MAX_VALUE; Set<Constructor<?>> ambiguousConstructors = null; LinkedList<UnsatisfiedDependencyException> causes = null; for (Constructor<?> candidate : candidates) { Class<?>[] paramTypes = candidate.getParameterTypes(); if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) { // 已经找到满足的构造参数,就返回 break; } if (paramTypes.length < minNrOfArgs) { //参数个数不相等 continue; } ArgumentsHolder argsHolder; if (resolvedValues != null) { //有参数则根据值构造对应参数类型的参数 try { //注释上获取参数名称 String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length); if (paramNames == null) { //获取参数名称探索器 ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer(); if (pnd != null) { //获取指定构造函数的参数名称 paramNames = pnd.getParameterNames(candidate); } } //根据参数和数据类型创建参数持有者 argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames, getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1); } catch (UnsatisfiedDependencyException ex) { if (logger.isTraceEnabled()) { logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex); } // Swallow and try next constructor. if (causes == null) { causes = new LinkedList<>(); } causes.add(ex); continue; } } else { //给定的显式参数->参数长度必须完全匹配。 if (paramTypes.length != explicitArgs.length) { continue; } //构造函数没有参数的情况 argsHolder = new ArgumentsHolder(explicitArgs); } //探测是否有不确定的构造函数存在,例如不同构造函数的参数为父子关系 int typeDiffWeight = (mbd.isLenientConstructorResolution() ? argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes)); // 如果表示最接近的匹配,则选择此构造函数。 if (typeDiffWeight < minTypeDiffWeight) { constructorToUse = candidate; argsHolderToUse = argsHolder; argsToUse = argsHolder.arguments; minTypeDiffWeight = typeDiffWeight; ambiguousConstructors = null; } else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) { if (ambiguousConstructors == null) { ambiguousConstructors = new LinkedHashSet<>(); ambiguousConstructors.add(constructorToUse); } ambiguousConstructors.add(candidate); } } if (constructorToUse == null) { if (causes != null) { UnsatisfiedDependencyException ex = causes.removeLast(); for (Exception cause : causes) { this.beanFactory.onSuppressedException(cause); } throw ex; } throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Could not resolve matching constructor " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)"); } else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Ambiguous constructor matches found in bean '" + beanName + "' " + "(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " + ambiguousConstructors); } if (explicitArgs == null && argsHolderToUse != null) { //将解析的构造函数加入缓存 argsHolderToUse.storeCache(mbd, constructorToUse); } } Assert.state(argsToUse != null, "Unresolved constructor arguments"); //将构建的实例加入到BeanWrapper中 bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse)); return bw; }
逻辑很复杂,函数的代码量很大。我们来总览一下整个函数:
(1)构造函数参数的确定;
1.根据explicitArgs参数判断。
如果传入的参数explicitArgs不为空,那边可以直接确定参数,因为explicitArgs参数是在调用bean的时候用户指定的,在BeanFactory类中存在这样的方法:
Object getBean(String name, Object... args) throws BeansException;
在获取bean的时候,用户不但可以指定bean的名称还可以指定bean所对应类的构造函数或者工厂方法的方法参数,主要用于静态工厂方法的调用,而这里是需要给定完全匹配的参数的,所以,便可以判断,如果传入参数explicitArgs不为空,则可以确定构造函数参数就是它。
2.缓存中获取。
除此之外,确定参数的办法如果之前已经分析过,也就是说构造函数参数已经记录在缓存中,那么便可以直接拿来使用。而且,这里要提到的是,在缓存中缓存的可能是参数的最终类型也可能是参数的初始类型,例如:构造函数参数要求的是int类型,但是原始的参数值可能是String类型的“1”,那么即使在缓存中得到了参数,也需要经过类型转换器的过滤以确保参数类型与对应的构造函数参数类型完全对应。
3.配置文件获取。
如果不能根据传入的参数explicitArgs确定构造函数的参数也无法在缓存中得到相关的信息,那么就只能开始新一轮的分析了。
分析从获取配置文件中的配置的构造函数信息开始,经过之前的分析,我们知道,Spring中配置文件中的信息经过转换都会通过BeanDefinition实例来承载,也就是参数mbd中包含,那么可以通过调用mbd.getConstrutorArgumentValues()来获取配置的构造函数信息。有了配置中的信息便可以获取对应的参数值信息了,获取参数值的信息包括直接指定值,如:直接指定构造函数中的某个值为原始类型String类型,或者是一个对其他bean的引用,而这一处理委托给resolveConstructorArguments方法,并返回能解析到的参数的个数。
(2)构造函数的确定。
经过了第一步之后已经确定了构造函数的参数,接下来的任务就是根据构造函数参数在所有构造函数中锁定对应的构造函数,而匹配的方法就是根据参数个数匹配,所以在匹配之前需要先对构造函数按照public构造函数优先参数数量降序。这样可以在遍历的情况下迅速判断排在后面的构造函数参数个数是否符合条件。
由于在配置文件中并不是唯一限制使用参数位置索引的方式去创建,同样还支持指定参数名称进行设定参数值的情况,如<constructor-arg name="a"> ,那么这种情况下就需要首先确定构造函数中的参数名称。
获取参数名称可以有两种方式,一种是通过注解的方式直接获取,另一种就是使用Spring中提供的工具类ParameterNameDiscoverer来获取。构造函数、参数名称、参数类型、参数值都可以确定后就可以锁定构造函数以及转换对应的参数类型了。
(3)根据确定的构造函数转换对应的参数类型;
主要是使用Spring中提供的类型转换器或者用户自定义类型转换器进行转换。
(4)构造函数不确定性的验证;
当然有时候即使构造函数、参数名称、参数类型、参数值都确定后也不一定会直接锁定构造函数,不同构造函数的参数为父子关系,所以Spring在最后又做了一次验证。
(5)根据实例化策略以及得到的构造函数及构造函数参数实例化bean。
2.instantiateBean
相信在了解了带参数的构造函数实例构造,理解不带参数的构造函数将是非常愉快的过程:
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); } }
发现,此方法并没有什么实质性的逻辑,直接调用实例化策略进行实例化就可以了。
3.实例化策略
在上述实例化的过程中反复的提到过实例化策略,那这又是做什么用的呢?其实,经过前面的分析,我们已经得到了足以实例化的所有相关的信息,完全可以使用最简单的反射方法来构造实例对象,但是Spring却并没有这么做。
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) { // 如果有需要覆盖或者动态替换的方法则当然需要使用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. return instantiateWithMethodInjection(bd, beanName, owner); } }
看了上面的函数后似乎能感受到Spring的用心良苦,为了能更方便的使用Spring而做了大量的工作。
在程序中,首先判断了BeanDefinition.getMethodOverrides()为空也就是用户没有使用replace或者lookup的配置方法,那么直接使用反射的方式,简单快捷,但是如果使用了这两个特性,再直接使用反射的方式就不妥了,因为需要将这两个配置提供的功能切入进去,所以就必须要使用动态代理的方式将包含两个特性所对应的逻辑拦截增强器设置进去,这样才可以保证在调用方法的时候会被相应的拦截器增强,返回值为包含拦截器的代理实例。
2 记录创建bean的ObjectFactory
在doCreateBean函数中有这样的一段代码:
//是否需要提早曝光:单例 && 允许循环依赖 && 当前bean正在创建中,判断是否有循环依赖 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //为了避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }
上述第一段代码时doCreateBean方法中的,第二段是getEarlyBeanReference方法的实现。
这段代码逻辑其实不复杂,但是却不是很好理解,我们需要从全局的角度去思考Spring的依赖解决办法:
❤ earlySingletonExposure:从字面上的意思理解就是提早曝光的单例,我们暂时不定义它的学名叫什么,我们感兴趣的是有哪些条件影响这个值;
❤ mbd.isSingleton():判断此RootBeanDefinition代表的是否是单例;
❤ this.allowCircularReferences:是否允许循环依赖,此属性不再配置文件中配置,是在AbstractRefreshableApplicationContext 中提供了设置函数,可以通过硬编码的方式进行设置或者可以通过自定义命名空间进行设置,其中硬编码的方式如下:
ClassPathXmlApplicationContext bf = new ClassPathXmlApplicationContext("spring.xml"); bf.setAllowBeanDefinitionOverriding(false);
❤ isSingletonCurrentlyCreation(beanName):该bean是否在创建中。在Spring中,会有个专门的属性默认为DefaultSingletonBeanRegistry 的singletonsCurrentlyInCreation来记录bean的加载状态,在bean开始创建前会将beanName记录在属性中,在bean创建结束后会将beanName从属性中移除。那么我们跟随代码一路走来,其实对这个属性的记录并没有什么印象,那么这个状态是在那里记录的呢?不同的scope的记录位置并不一样,以singleton为例,在singleton下记录属性的函数是在DefaultSingletonBeanRegistry类的getSingleton(String beanName,ObjectFactory singletonFactory)函数的beforeSingletonCreation(beanName)和afterSingletonCreation(beanName)与this.singletonsCurrentlyInCreation.remove(beanName)来进行状态的记录与移除。
经过以上的分析我们了解了变量earlySingletonExposure是否是单例、是否允许循环依赖、是否对应的bean正在创建的条件的综合。当这三个条件都满足时会执行addSingletonFactory操作,那么加入SingletonFactory的作用是什么呢?又是在什么时候调用呢?
我们以最简单的AB循环依赖为例,类A中有属性类B,类B中有属性类A,那么初始化beanA的过程如下图所示:
上图展示了创建beanA的流程,从图中我们可以看到,在创建A的时候首先会记录类A所对应的beanName,并将beanA的创建工厂加入到缓存中,而在对A的属性填充也就是调用populateBean方法的时候又再一次的对B进行递归创建。同样的,因为在B中存在A的属性,因此在实例化B的时候在执行populateBean的时候又会再次初始化A,也就是图形的最后,调用getBean(A)。关键就是在这里,在这个函数中并不是至二级实例化A,而是先去缓存中检测是否已经有创建好的对应的bean,或者是否已经创建好的ObjectFactory,而此时对于A的ObjectFactory早就已经创建好了,所以便不会再去执行创建A,而是直接调用ObjectFactory去创建A。
这篇文章讲述了创建bean的大致所有步骤和对创建bean中的步骤:创建bean的实例和记录bean的ObjectFactory,下篇文章会继续讲述创建bean的其他步骤。
参考:《Spring源码深度解析》 郝佳 编著: