基于 Spring Framework v5.2.6.RELEASE
这篇内容是补充之前在 BeanFactory 初始化 一文中留的一个坑,前文提到了 BeanFactory 的实例化是在 AbstractRefreshableApplicationContext#createBeanFactory
方法中完成的,这里会通过构造方法创建一个 DefaultListableBeanFactory
类型的 BeanFactory,如下:
protectedDefaultListableBeanFactorycreateBeanFactory() { returnnewDefaultListableBeanFactory(getInternalParentBeanFactory()); }
这里的 getInternalParentBeanFactory()
获取的是当前容器的父容器对应的 BeanFactory,如果读过之前的相关文章就会知道,在创建当前容器的时候,父容器是空的。
DefaultListableBeanFactory
的构造方法源码如下:
publicDefaultListableBeanFactory(BeanFactoryparentBeanFactory) { super(parentBeanFactory); }
这里直接调用了父类 AbstractAutowireCapableBeanFactory
的构造方法:
publicAbstractAutowireCapableBeanFactory(BeanFactoryparentBeanFactory) { this(); setParentBeanFactory(parentBeanFactory); }
代码中有两个步骤,这篇文章主要分析一下这两部分的源码。
顺便把 DefaultListableBeanFactory
的类继承关系放在这里供参考:
无参构造方法
第一个步骤,是调用了本身的无参构造方法,源码如下:
publicAbstractAutowireCapableBeanFactory() { super(); ignoreDependencyInterface(BeanNameAware.class); ignoreDependencyInterface(BeanFactoryAware.class); ignoreDependencyInterface(BeanClassLoaderAware.class); }
这里首先调用了父类的构造方法,不过父类的构造方法是一个空方法,因此我们重点关注下面的逻辑,也就是 3 次 ignoreDependencyInterface
方法的调用。我们查看 ignoreDependencyInterface
的源码:
publicvoidignoreDependencyInterface(Class<?>ifc) { this.ignoredDependencyInterfaces.add(ifc); }
逻辑很简单,就是当前的 BeanFactory 有一个集合类型的成员变量 ignoredDependencyInterfaces
,三次调用这个方法就是把 BeanNameAware
、BeanFactoryAware
、BeanClassLoaderAware
这三个接口放在了这个集合里面。
接下来,我们的任务就是分析出将接口放在 ignoredDependencyInterfaces
的作用是什么。
感知接口
先看被添加到 ignoredDependencyInterfaces
中的三个接口。
这三个接口的名字都是 XXXAware
,都继承自 Aware
接口,并且都只包含一个与接口名对应的 setXXX
方法。
相信使用 Spring 框架的小伙伴对 Aware 接口都非常了解,这里在简单总结一下。
在 Spring 中,Aware 接口也被叫做感知接口,当一个 Bean 实现了感知接口的时候,Spring 创建 Bean 的时候,就会通过调用感知接口的方法注入相应的数据。
举个例子,我需要在一个 Bean 中使用当前 Bean 在 Spring 容器中的名称,也就是 beanName
,那么,我在开发这个类的时候,就可以实现 BeanNameAware
接口,并实现其 setBeanName(String name)
方法。当 Spring 实例化这个类的时候,发现其实现了 BeanNameAware
接口,然后,就会通过调用 setBeanName
方法,将 Bean 的名称传递进来。
更详细的流程,等到之后的代码分析中再探讨。
忽略指定接口的自动感知功能
了解了感知接口及其作用,我们再来看 ignoredDependencyInterfaces
的作用。通过在 IDE 中查找 ignoredDependencyInterfaces
的用法,发现除了调用 add
和 addAll
方法向集合中添加接口意外,只有 isExcludedFromDependencyCheck
方法地方用到了它:
我们找到这个方法的源码:
/*** Determine whether the given bean property is excluded from dependency checks.* <p>This implementation excludes properties defined by CGLIB and* properties whose type matches an ignored dependency type or which* are defined by an ignored dependency interface.* @param pd the PropertyDescriptor of the bean property* @return whether the bean property is excluded* @see #ignoreDependencyType(Class)* @see #ignoreDependencyInterface(Class)*/protectedbooleanisExcludedFromDependencyCheck(PropertyDescriptorpd) { return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces)); }
根据方法的名称和注释判断,这个方法的作用是判断一个 Bean 的成员变量是否要从依赖检查中排除掉。我们只看跟 ignoredDependencyInterfaces
有关的最后一个判断条件:
AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces)
被调用的 AutowireUtils.isSetterDefinedInInterface
方法的源码如下:
/*** Return whether the setter method of the given bean property is defined* in any of the given interfaces.* @param pd the PropertyDescriptor of the bean property* @param interfaces the Set of interfaces (Class objects)* @return whether the setter method is defined by an interface*/publicstaticbooleanisSetterDefinedInInterface(PropertyDescriptorpd, Set<Class<?>>interfaces) { Methodsetter=pd.getWriteMethod(); if (setter!=null) { Class<?>targetClass=setter.getDeclaringClass(); for (Class<?>ifc : interfaces) { if (ifc.isAssignableFrom(targetClass) &&ClassUtils.hasMethod(ifc, setter)) { returntrue; } } } returnfalse; }
方法中传入的两个参数,一个表示要进行判断的属性,另一个则是 ignoredDependencyInterfaces
。首先,获取给定属性的 setter
方法及其对应的类,遍历 ignoredDependencyInterfaces
中的每一个接口,并判断这个类是否实现了当前遍历到的接口,以及接口中是否包含同样的 setter
方法。如果以上两个判断的结果都是 true
,整个方法的返回值也就是 true
,就代表这个属性需要通过感知接口的方法来进行诸如,Spring 就不会在创建这个 Bean 的时候通过自动装配来给这个属性注入值。
setParentBeanFactory
第二个步骤是通过调用 parentBeanFactory
将构造方法参数中的 parentBeanFactory
赋值给对应的成员变量:
publicvoidsetParentBeanFactory(BeanFactoryparentBeanFactory) { if (this.parentBeanFactory!=null&&this.parentBeanFactory!=parentBeanFactory) { thrownewIllegalStateException("Already associated with parent BeanFactory: "+this.parentBeanFactory); } if (this==parentBeanFactory) { thrownewIllegalStateException("Cannot set parent bean factory to self"); } this.parentBeanFactory=parentBeanFactory; }
这一步骤比较简单。
这部分代码就分析到这里,关于 Spring 实例化 Bean 的具体步骤,会在之后的文章中进行分析,敬请关注。