前言
在Spring IOC源码分析过程中,会反复的提到一个类BeanDefinition。在Spring中,对于Bean的创建泉源有很多种方式,比如,使用xml配置,使用@configration配置,使用@Bean主键等。不同的Bean还有着不同的依赖,如何来定义这些Bean呢,Spring提供了BeanDefinition来做如许的事情。
Bean的定义重要由BeanDefinition来描述的。作为Spring中用于包装Bean的数据结构,让小编来待着大家看看面纱下的真容吧。
BeanDefinition定义
首先就是BeanDefinition的定义:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement1.从源码中给出的注释可以看出来,BeanDefinition作为定义Spring中Bean的接口,可以说是Bean的抽象数据结构,包罗属性参数,构造器参数,以及详细实现的进一步信息。
BeanDefinition结构
先来看一下BeanDefinition的继承结构图,如下:
观看BeanDefinition的继承结构最大的感触就是,整个继承关系职责分明,层层叠进。如果仔细观看Spring源码的话,会发现如许的设计是随处可见。
一个BeanDefinition描述了一个Bean的实例,包罗属性值,构造方法参数值和继承自它的类的更多信息。对于顶层接口BeanDefinition的设计,Spring的开发者们通过对于Bean定义描述需要具备的行为和功能进行分析建模,设计出一套同一抽象的模子。如果熟悉DDD的朋侪会发现这是领域分析建模的成果。在Spring源码里面对抽象接口的设计比力美满且具备参考价值,有很多值得学习的地方。我们可以在阅读Spring源码的同时对于其中的一些设计进行分析和思索,然后总结出自己的方法,累积经验。
AbstractBeanDefinition抽象类为BeanDefinition接口的部门方法提供同一的实现。然后下面的子类是实际具备业务含义的类比如RootBeanDefinition、ChildBeanDefinition等是根据详细的业务需求实现或者重定义其中的某些行为(固然整个过程是在服从BeanDefinition的领域边界内进行的)。下面会对这些类进行逐一的解析。
首先从类图中可以看出BeanDefinition继承了AttributeAccessor和BeanMetadataElement两个接口;稍微提一下这里应该是使用了接口隔离的原则,在Spring中也是可以随处可见如许的一个设计,这是为了更好的实现单一职责而做出的努力。
AttributeAccessor
重要用于定义附加和访问元数据的通用的接口
// 定义用于附加和访问元数据的通用的接口,来自任意对象public interface AttributeAccessor { // 设置属性的值 void setAttribute(String name, @Nullable Object value); // 得到指定属性名称的值,如果不存在返回null @Nullable Object getAttribute(String name); // 删除指定的name的属性,如果不存在则返回null @Nullable Object removeAttribute(String name); // 判断指定的属性名称是否存在,注意属性名称必须是唯一的 boolean hasAttribute(String name); // 得到所有属性的名称 String[] attributeNames();}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.BeanMetadataElement
元数据,返回Bean的泉源,BeanMetadataElement只有一个方法,该方法返回可配置源的对象。
这个方法在@Configuration中使用较多,由于他会被代理
public interface BeanMetadataElement { // 返回可配置源对象 @Nullable default Object getSource() { return null; }}1.2.3.4.5.6.7.通过对AttributeAccessor和BeanMetadataElement 两个接口的介绍基本上可以看出来,BeanDefinition实现了这两个接口其实就是具备对应的行为和属性,重要是对于属性和参数的存储和相关的源对象的生存。
BeanDefinition源码
介绍完AttributeAccessor和BeanMetadataElement 的接口(前面也说了这是一种单一职责的体现)。BeanDefinition仅仅是一个最简朴的接口,重要功能是答应BeanFactoryPostProcessor,例如PropertyPlaceHolderConfigure可以或许检索并修改属性值和别的Bean的元数据,下面来看一下BeanDefinition的源码实际上包罗哪些内容。(Spring的注释比力详细,这里考虑文章篇幅,部门注解自己做了一下删减)
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { //表示bean的作用域是单例还是原型模式 String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; /** * bean的角色 */ // 默认,为应用程序定义 int ROLE_APPLICATION = 0; // 做为大量配置的一部门(支持、扩展类) 实际上就是说,我这个Bean是用户的,是从配置文件中过来的 int ROLE_SUPPORT = 1; // 指内部工作的基础构造 实际上是说我这Bean是Spring自己的,和你用户没有一毛钱关系 int ROLE_INFRASTRUCTURE = 2; // Modifiable attributes // 如果存在父类bean的话将名称设置进去 void setParentName(@Nullable String parentName); @Nullable String getParentName(); // 指定这个bean定义的bean类名。类名可以在bean工厂后期处置惩罚时修改,通常用解析后的类名替换原来的类名。 void setBeanClassName(@Nullable String beanClassName); @Nullable String getBeanClassName(); // 上面设置的原型还是单例SCOPE_SINGLETON or SCOPE_PROTOTYPE void setScope(@Nullable String scope); @Nullable String getScope(); // 设置是否懒加载,如果设置为false容器启动的时候就会加载单例bean,true只有当需要的时候才会加载bean void setLazyInit(boolean lazyInit); boolean isLazyInit(); /** * dependsOn一般用于两个bean之间没有表现依赖,但后一个Bean需要用到前一个Bean实行初始方法后的结果。例如在< bean id=“a” dependsOn=“b”/> 时 * 在初始化a时首先先初始化b,在烧毁b之前会先烧毁a。 */ void setDependsOn(@Nullable String... dependsOn); @Nullable String[] getDependsOn(); // 这个Bean是否答应被自动注入到别的地方去(默认都是被答应的) // 注意:此标志只影响按类型装配,不影响byName的注入方式的 // no:不使用自动装配,必须通过ref元素指定依赖,为autowire默认值。 // byName:使用属性名自动装配,如果存在一个与指定属性名相同类型的bean则自动装配,如果有多个,则抛 // 出异常。 // byType:根据类型自动状态,如果存在与指定属性类型相同的bean,则自动装配,如果有多个,则抛出异常。 // constructor:与byType雷同,不同之处在于它使用的是构造器的参数类型。 // autodetect:通过bean的自省机制来决定是使用constructor还是byType来进行自动装配。如果有默认构造 // 器,则使用byType,否则使用constructor。 void setAutowireCandidate(boolean autowireCandidate); boolean isAutowireCandidate(); //如果其他对象按照类型自动装配时发现有多个符合类型的多个实现bean,如果bean的primary属性为true, //则以primary为true的优先,固然如果有多个primary为true,则抛出异常。 // @Primary void setPrimary(boolean primary); boolean isPrimary(); // 设置bean的factoryBeanName void setFactoryBeanName(@Nullable String factoryBeanName); @Nullable String getFactoryBeanName(); //指定工厂方法~ void setFactoryMethodName(@Nullable String factoryMethodName); @Nullable String getFactoryMethodName(); // 返回bean构造函数参数 ConstructorArgumentValues getConstructorArgumentValues(); default boolean hasConstructorArgumentValues() { return !getConstructorArgumentValues().isEmpty(); } // 属性聚集 MutablePropertyValues getPropertyValues(); default boolean hasPropertyValues() { return !getPropertyValues().isEmpty(); } /** * Set the name of the initializer method. * @since 5.1 */ void setInitMethodName(@Nullable String initMethodName); /** * Return the name of the initializer method. * @since 5.1 */ @Nullable String getInitMethodName(); /** * Set the name of the destroy method. * @since 5.1 */ void setDestroyMethodName(@Nullable String destroyMethodName); /** * Return the name of the destroy method. * @since 5.1 */ @Nullable String getDestroyMethodName(); // 对应上面设置的角色 void setRole(int role); int getRole(); // @Description void setDescription(@Nullable String description); @Nullable String getDescription(); // Read-only attributes ResolvableType getResolvableType(); boolean isSingleton(); boolean isPrototype(); // 返回bean对象是否是抽象类,抽象类不需要实例化 boolean isAbstract(); /** * Return a description of the resource that this bean definition * came from (for the purpose of showing context in case of errors). */ @Nullable String getResourceDescription(); //返回原始BeanDefinition,如果没有则返回@null // 若这个Bean定义被代理、修饰过 这个方法可以返回原始的 @Nullable BeanDefinition getOriginatingBeanDefinition();}1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.108.109.110.111.112.113.114.115.116.117.118.119.120.121.122.123.124.125.126.127.128.129.130.131.132.133.134.135.136.137.138.139.140.这里的话可以仔细看看BeanDefinition的设计,对于Bean的描述,Spring是如何通过BeanDefinition如许一个对象来对其进行描述的。后期就是通过描述对象来决定如何实例化Bean对象。其实可以思索一下如果是我们来设计如许一个类会如何设计,spring又是如何设计,这之间的差距在什么地方。
固然这整个过程完全对应这中的相关的配置属性,或者是@bean中的相关注解一一对应的。
AbstractBeanDefinition源码
考虑到整个源码量比力大,这里分开展示出来解析
1.// 默认单例 public static final String SCOPE_DEFAULT = ""; // 自动装配的一些常量 public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO; public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR; @Deprecated public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;1.2.3.4.5.6.7.8.9.10.SCOPE_DEFAULT 设置默认的Bean的Scope,对应BeanDefinition中ConfigurableBeanFactory.SCOPE_SINGLETON和ConfigurableBeanFactory.SCOPE_PROTOTYPE
设置的自动装配的相关常量:
- no:不使用自动装配,必须通过ref元素指定依赖,为autowire默认值。
- byName:使用属性名自动装配,如果存在一个与指定属性名相同类型的bean则自动装配,如果有多个,则抛出异常。
- byType:根据类型自动状态,如果存在与指定属性类型相同的bean,则自动装配,如果有多个,则抛出异常。
- constructor:与byType雷同,不同之处在于它使用的是构造器的参数类型。
- autodetect:通过bean的自省机制来决定是使用constructor还是byType来进行自动装配。如果有默认构造器,则使用byType,否则使用constructor。
1. // 检查依赖是否正当,默认不进行检查 public static final int DEPENDENCY_CHECK_NONE = 0; // 依赖类型是对象引用需要检查 public static final int DEPENDENCY_CHECK_OBJECTS = 1; // 对简朴的属性依赖进行检查 public static final int DEPENDENCY_CHECK_SIMPLE = 2; // 对所有属性依赖进行检查 public static final int DEPENDENCY_CHECK_ALL = 3; 1.2.3.4.5.6.7.8.对依赖进行按需检查,根据不同的配置可以实现不同的检查方式。对应的解析如以上代码注释所示。
/** * Constant that indicates the container should attempt to infer the * {@link #setDestroyMethodName destroy method name} for a bean as opposed to * explicit specification of a method name. The value {@value} is specifically * designed to include characters otherwise illegal in a method name, ensuring * no possibility of collisions with legitimately named methods having the same * name. *
Currently, the method names detected during destroy method inference * are "close" and "shutdown", if present on the specific bean class. * 若Bean未指定烧毁方法,容器应该尝试推断Bean的烧毁方法的名字,目前来说,推断的烧毁方法的名字一般为close或是shutdown *(即未指定Bean的烧毁方法,但是内部定义了名为close或是shutdown的方法,则容器推断其为烧毁方法) */ public static final String INFER_METHOD = "(inferred)"; // bean的class对象或者类的权限定名 @Nullable private volatile Object beanClass; // 默认单例 @Nullable private String scope = SCOPE_DEFAULT; // 不然不是抽象类 private boolean abstractFlag = false; // 默认不是懒加载 @Nullable private Boolean lazyInit; // 默认不进行自动装配 private int autowireMode = AUTOWIRE_NO; // 默认不进行依赖检查 private int dependencyCheck = DEPENDENCY_CHECK_NONE; @Nullable private String[] dependsOn; // autowire-candidate属性设置为false,如许容器在查找自动装配对象时,将不考虑该bean, // 备注:并不影响本身注入别的的Bean private boolean autowireCandidate = true; // 默认不是主bean private boolean primary = false; //用于记录Qualifier,对应子元素qualifier=======这个字段有必要解释一下 // 唯一向这个字段放值的方法为本类的:public void addQualifier(AutowireCandidateQualifier qualifier) copyQualifiersFrom这个不算,那属于拷贝 // 调用处:AnnotatedBeanDefinitionReader#doRegisterBean 但是Spring所有调用处,qualifiers字段传的都是null~~~~~~~~~尴尬 // 通过我多放跟踪发现,此处这个字段目前【永久】不会被赋值(除非我们手动调用对应方法为其赋值) 但是有大概我才疏学浅,若有知道的 请告知,非常非常感谢 我考虑到它大概是预留字段~~~~ // 我起初以为如许可以赋值: //@Qualifier("aaa") //@Service //public class HelloServiceImpl 没想到,也是欠好使的,Bean定义里面也不会有值 // 因此对应的方法getQualifier和getQualifiers 目前应该基本上都返回null或者[] private final Map qualifiers = new LinkedHashMap(); //用于记录Qualifier,对应子元素qualifier=======这个字段有必要解释一下 // 唯一向这个字段放值的方法为本类的:public void addQualifier(AutowireCandidateQualifier qualifier) copyQualifiersFrom这个不算,那属于拷贝 // 调用处:AnnotatedBeanDefinitionReader#doRegisterBean 但是Spring所有调用处,qualifiers字段传的都是null~~~~~~~~~尴尬 // 通过我多放跟踪发现,此处这个字段目前【永久】不会被赋值(除非我们手动调用对应方法为其赋值) 但是有大概我才疏学浅,若有知道的 请告知,非常非常感谢 我考虑到它大概是预留字段~~~~ // 我起初以为如许可以赋值: //@Qualifier("aaa") //@Service //public class HelloServiceImpl 没想到,也是欠好使的,Bean定义里面也不会有值 // 因此对应的方法getQualifier和getQualifiers 目前应该基本上都返回null或者[] private final Map qualifiers = new LinkedHashMap(0); //我理解为通过这个函数的逻辑初始化Bean,而不是构造函数或是工厂方法(相当于自己去实例化,而不是交给Bean工厂) @Nullable private Supplier instanceSupplier; //是否答应访问非public方法和属性,应用于构造函数、工厂方法、init、destroy方法的解析 默认是true,表示啥都可以访问 private boolean nonPublicAccessAllowed = true; // 是否以一种宽松的模式解析构造函数,默以为true(宽松和严格体现在类型匹配上) private boolean lenientConstructorResolution = true; //工厂类名(注意是String类型,不是Class类型) 对应bean属性factory-method @Nullable private String factoryBeanName; //工厂方法名(注意是String类型,不是Method类型) @Nullable private String factoryMethodName; //记录构造函数注入属性,对应bean属性constructor-arg @Nullable private ConstructorArgumentValues constructorArgumentValues; //Bean属性的名称以及对应的值,这里不会存放构造函数相关的参数值,只会存放通过setter注入的依赖 @Nullable private MutablePropertyValues propertyValues; //方法重写的持有者,记录lookup-method、replaced-method元素 @Lookup等 @Nullable private MethodOverrides methodOverrides; //init函数的名字 @Nullable private String initMethodName; //destory函数的名字 @Nullable private String destroyMethodName; //是否实行init-method,程序设置 private boolean enforceInitMethod = true; private boolean enforceDestroyMethod = true; //是否是合成类(是不是应用自定义的,例如生成AOP代理时,会用到某些辅助类,这些辅助类不是应用自定义的,这个就是合成类) //创建AOP时候为true private boolean synthetic = false; //Bean的角色,为用户自定义Bean private int role = BeanDefinition.ROLE_APPLICATION; // Bean的描述信息 @Nullable private String description; //the resource that this bean definition came from // 这个Bean哪儿来的 @Nullable private Resource resource;1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106. 1.(注释相关内容复制网上 【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...))
- MutablePropertyValues:对于这个类存放的是Bean相关的属性值,就是get/set方法对于的值。
我仔细观察这里的对象重要是分为两大类,
- 是对Bean的一些配置的描述,比如如何创建Bean,或者Bean是否具备某些特性;
- 是Bean自身的属性值的定义MutablePropertyValues
我感觉Spring的这种设计还是比力符合类组合的思想,将不同功能的类相互组合最后完成对于一个Bean的详细描述,可以说是从创建-》初始化-》烧毁。贯穿了Bean在Spring中整个生命周期的一些配置和描述吧。
总结一下以上的AbstractBeanDefinition具备的基本属性值,并对其进行了注释,其中也参考了相关资料。通过源码可以了解到AbstractBeanDefinition定义了Bean描述的属性,通过这个类可以看到对bean描述的相关属性的默认配置。
对于AbstractBeanDefinition抽象类其重要还是为BeanDefinition接口实现一套通用的属性描述。为详细的子类如GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition实现提供更多的便捷,将公共的部门提取到抽象类中实现。这个应该是抽象类使用的比力多的一种场景吧。固然详细关于抽象类和接口直接的异同优劣这里不详细阐述。
接下来看一下详细衍生出来的实现类了,先看一下GenericBeanDefinition、RootBeanDefinition、ChildBeanDefinition。他们都是直接实现了AbstractBeanDefinition。
GenericBeanDefinition
GenericBeanDefinition是尺度BeanDefinition的实现类,和任何其他Bean定义一样除了具有可选的构造函数参数值和属性值外,还可以通过设置“parentName”来设置parent BeanDefinition。源码如下所示:
@SuppressWarnings("serial")public class GenericBeanDefinition extends AbstractBeanDefinition { @Nullable private String parentName; /** * Create a new GenericBeanDefinition, to be configured through its bean * properties and configuration methods. * @see #setBeanClass * @see #setScope * @see #setConstructorArgumentValues * @see #setPropertyValues */ public GenericBeanDefinition() { super(); } /** * Create a new GenericBeanDefinition as deep copy of the given * bean definition. * @param original the original bean definition to copy from */ public GenericBeanDefinition(BeanDefinition original) { super(original); } @Override public void setParentName(@Nullable String parentName) { this.parentName = parentName; } @Override @Nullable public String getParentName() { return this.parentName; } @Override public AbstractBeanDefinition cloneBeanDefinition() { return new GenericBeanDefinition(this); } @Override public boolean equals(@Nullable Object other) { if (this == other) { return true; } if (!(other instanceof GenericBeanDefinition)) { return false; } GenericBeanDefinition that = (GenericBeanDefinition) other; return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other)); } @Override public String toString() { if (this.parentName != null) { return "Generic bean with parent '" + this.parentName + "': " + super.toString(); } return "Generic bean: " + super.toString(); }} 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.GenericBeanDefinition的源码比力简朴,只是增长了一个parentName的属性值,其余的实现都是在AbstractBeanDefinition中。在xml中配置的bean,被添加进来的时候都是GenericBeanDefinition类型。如下
1. // BeanDefinitionParserDelegate.java public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, @Nullable BeanDefinition containingBean) { // 省略代码部门代码 try { //1. 根据类名创建对应的BeanDefinition对象 AbstractBeanDefinition bd = createBeanDefinition(className, parent); parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); parseMetaElements(ele, bd); parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); parseConstructorArgElements(ele, bd); parsePropertyElements(ele, bd); parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)方法中有着这么一行代码。(关于BeanDefinitionParserDelegate在后面spring BeanDefinition注册中会详细的讲解)
//1. 根据类名创建对应的BeanDefinition对象AbstractBeanDefinition bd = createBeanDefinition(className, parent);1.2.我们在看一下这行代码createBeanDefinition,跟踪进去看一下
1. // BeanDefinitionParserDelegate.java protected AbstractBeanDefinition createBeanDefinition(@Nullable String className, @Nullable String parentName) throws ClassNotFoundException { return BeanDefinitionReaderUtils.createBeanDefinition( parentName, className, this.readerContext.getBeanClassLoader()); }1.2.3.4.5.6.7.我们可以看到BeanDefinitionReaderUtils这个工具类,重要是通过他来创建详细的BeanDefinition对象
//BeanDefinitionReaderUtils.java public static AbstractBeanDefinition createBeanDefinition( @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException { GenericBeanDefinition bd = new GenericBeanDefinition(); bd.setParentName(parentName); if (className != null) { if (classLoader != null) { bd.setBeanClass(ClassUtils.forName(className, classLoader)); } else { bd.setBeanClassName(className); } } return bd; } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.到这里基本上可以看到在xml中配置的Bean,最初会被解析成GenericBeanDefinition。
刚刚说到GenericBeanDefinition的parentName,这里要解释一下parent指向的类不是子类继承父类的意思。对于这个parent的必要条件这里提一下重要两点:
- 子Bean必须与父Bean保持兼容,也就是说子Bean中必须有父Bean定义的所有属性
- 父Bean必须是抽象Bean或者定义了lazy-init=true也就是不让Bean工厂实例化该Bean
ChildBeanDefinition
ChildBeanDefinition继承父类设置的Bean的定义,对父Bean(RootBeanDefinition)定义有固定的依赖关系。他将从父Bean继承构造函数的参数,属性值和可覆盖的方法和选择添加新的值。
注意:Spring 2.5以来,注册bean的首选方式定义是GenericBeanDefinition类,答应动态定义父依赖GenericBeanDefinition#setParentName,这有效地在大多数用例中替换ChildBeanDefinition类。
public class ChildBeanDefinition extends AbstractBeanDefinition { @Nullable private String parentName; 1.2.3.4.5.从源码中也可以看到ChildBeanDefinition基本上和GenericBeanDefinition雷同。按照源码中的注释来看,基本上是推荐使用GenericBeanDefinition来替换ChildBeanDefinition了。
RootBeanDefinition
定义一个可合并的Bean定义,在Spring BeanFactory运行期间返回特定的Bean。它大概是从多个相互继承的原始bean定义创建的,通常还是建议使用GenericBeanDefinition。
public class RootBeanDefinition extends AbstractBeanDefinition { // 包罗了Bean的名称,别名,BeanDefinition @Nullable private BeanDefinitionHolder decoratedDefinition; // 检察Bean注解信息 @Nullable private AnnotatedElement qualifiedElement; // 确定是否需要进行合并 /** Determines if the definition needs to be re-merged. */ volatile boolean stale; // 答应合并 boolean allowCaching = true; // 工厂方法是否唯一 boolean isFactoryMethodUnique; // 用于反射 @Nullable volatile ResolvableType targetType; /** Package-visible field for caching the determined Class of a given bean definition. */ @Nullable volatile Class resolvedTargetType; /** Package-visible field for caching if the bean is a factory bean. */ @Nullable volatile Boolean isFactoryBean; /** Package-visible field for caching the return type of a generically typed factory method. */ @Nullable volatile ResolvableType factoryMethodReturnType; /** Package-visible field for caching a unique factory method candidate for introspection. */ @Nullable volatile Method factoryMethodToIntrospect; /** Package-visible field for caching a resolved destroy method name (also for inferred). */ @Nullable volatile String resolvedDestroyMethodName; /** Common lock for the four constructor fields below. */ final Object constructorArgumentLock = new Object(); /** Package-visible field for caching the resolved constructor or factory method. */ @Nullable Executable resolvedConstructorOrFactoryMethod; /** Package-visible field that marks the constructor arguments as resolved. */ boolean constructorArgumentsResolved = false; /** Package-visible field for caching fully resolved constructor arguments. */ @Nullable Object[] resolvedConstructorArguments; /** Package-visible field for caching partly prepared constructor arguments. */ @Nullable Object[] preparedConstructorArguments; /** Common lock for the two post-processing fields below. */ final Object postProcessingLock = new Object(); /** Package-visible field that indicates MergedBeanDefinitionPostProcessor having been applied. */ boolean postProcessed = false; /** Package-visible field that indicates a before-instantiation post-processor having kicked in. */ @Nullable volatile Boolean beforeInstantiationResolved; @Nullable private Set externallyManagedConfigMembers; @Nullable private Set externallyManagedInitMethods; @Nullable private Set externallyManagedDestroyMethods; 。。。。省略部门代码 } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.分析RootBeanDefiniiton的属性可以发现他对AbstractBeanDefinition做了新增,重要是针对一下几点:(参考 【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...))
- 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
- Bean的注解(AnnotatedElement)
- 详细的工厂方法(Class类型),包罗工厂方法的返回类型,工厂方法的Method对象
- 构造函数、构造函数形参类型
- Bean的class对象
可以看到,RootBeanDefinition与AbstractBeanDefinition是互补关系,RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本美满
关于RootBeanDefiniiton还有一个概念也很重要,那就是getMergedBeanDefinition,在Spring里面有一个很重要的代码如下:
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);1.要是阅读源码细心的朋侪应该在Spring里面都见过雷同的代码。那么这行代码详细是在做什么呢,下面详细分析一下。
MergedBeanDefinition生成
我们先来看一下AbstractBeanFactory#getMergedLocalBeanDefinition的代码,已这个为切入点,分析一下MergedBeanDefinition生成过程
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 && !mbd.stale) { return mbd; } return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); }1.2.3.4.5.6.7.8.上面的代码首先尝试从缓存中获取RootBeanDefinition,如果没有再通过getMergedBeanDefinition(beanName, getBeanDefinition(beanName))方法生成。其实可以看到核心代码在这里,我们一起跟踪进去看看。
protected RootBeanDefinition getMergedBeanDefinition( String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException { // 加锁防止出现并发问题 synchronized (this.mergedBeanDefinitions) { RootBeanDefinition mbd = null; RootBeanDefinition previous = null; // Check with full lock now in order to enforce the same merged instance. if (containingBd == null) { mbd = this.mergedBeanDefinitions.get(beanName); } if (mbd == null || mbd.stale) { previous = mbd; // 判断db是否有parentname,如果没有直接返回bd的克隆 // 当没有parentname的时候bd重要有两种类型 // 1.一个独立的GenericBeanDefinition // 2.一个RootBeanDefinition if (bd.getParentName() == null) { // Use copy of given root bean definition. if (bd instanceof RootBeanDefinition) { mbd = ((RootBeanDefinition) bd).cloneBeanDefinition(); } else { mbd = new RootBeanDefinition(bd); } } else { // Child bean definition: needs to be merged with parent. BeanDefinition pbd; try { String parentBeanName = transformedBeanName(bd.getParentName()); // 通过递归的方式由于bd有parent,他parent也大概有prent所以需要使用递归的方式 if (!beanName.equals(parentBeanName)) { pbd = getMergedBeanDefinition(parentBeanName); } else { BeanFactory parent = getParentBeanFactory(); if (parent instanceof ConfigurableBeanFactory) { pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName); } else { throw new NoSuchBeanDefinitionException(parentBeanName, "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName + "': cannot be resolved without a ConfigurableBeanFactory parent"); } } } catch (NoSuchBeanDefinitionException ex) { throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName, "Could not resolve parent bean definition '" + bd.getParentName() + "'", ex); } // Deep copy with overridden values. mbd = new RootBeanDefinition(pbd); mbd.overrideFrom(bd); } // Set default singleton scope, if not configured before. if (!StringUtils.hasLength(mbd.getScope())) { mbd.setScope(SCOPE_SINGLETON); } // A bean contained in a non-singleton bean cannot be a singleton itself. // Let's correct this on the fly here, since this might be the result of // parent-child merging for the outer bean, in which case the original inner bean // definition will not have inherited the merged outer bean's singleton status. if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) { mbd.setScope(containingBd.getScope()); } // Cache the merged bean definition for the time being // (it might still get re-merged later on in order to pick up metadata changes) if (containingBd == null && isCacheBeanMetadata()) { this.mergedBeanDefinitions.put(beanName, mbd); } } if (previous != null) { copyRelevantMergedBeanDefinitionCaches(previous, mbd); } return mbd; } } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.64.65.66.67.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.从上面的代码可以看出来,该过程是通过递归使用getMergedBeanDefinition(),将parent放置到中间pbd中,最后通过mbd = new RootBeanDefinition(pbd);将parent中属性和相关参数设置到一个最终的RootBeanDefinition中。重要做的事情下面几步:
- 判断BeanDefinition是否有parentname,如果没有大概会是一个GenericBeanDefinition或者RootBeanDefinition。直接将BeanDefinition返回即可
- 如果有parentName,通过递归的方式将RootBeanDefinition返回,最后通过new RootBeanDefinition(pbd);将父BeanDefinition和子BeanDefinition进行合并,返回一个新的RootBeanDefinition
下面在看一下RootBeanDefinition(BeanDefinition original)的构造方法,我们看看他是否真的可以将参数original属性和参数进行合并。
RootBeanDefinition(BeanDefinition original) { super(original); } 1.2.3.在看一下父类AbstractBeanDefinition的构造函数
// AbstractBeanDefinition.java /** * Create a new AbstractBeanDefinition as a deep copy of the given * bean definition. * @param original the original bean definition to copy from */ protected AbstractBeanDefinition(BeanDefinition original) { setParentName(original.getParentName()); setBeanClassName(original.getBeanClassName()); setScope(original.getScope()); setAbstract(original.isAbstract()); setFactoryBeanName(original.getFactoryBeanName()); setFactoryMethodName(original.getFactoryMethodName()); setRole(original.getRole()); setSource(original.getSource()); copyAttributesFrom(original); if (original instanceof AbstractBeanDefinition) { AbstractBeanDefinition originalAbd = (AbstractBeanDefinition) original; if (originalAbd.hasBeanClass()) { setBeanClass(originalAbd.getBeanClass()); } if (originalAbd.hasConstructorArgumentValues()) { setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues())); } if (originalAbd.hasPropertyValues()) { setPropertyValues(new MutablePropertyValues(original.getPropertyValues())); } if (originalAbd.hasMethodOverrides()) { setMethodOverrides(new MethodOverrides(originalAbd.getMethodOverrides())); } Boolean lazyInit = originalAbd.getLazyInit(); if (lazyInit != null) { setLazyInit(lazyInit); } setAutowireMode(originalAbd.getAutowireMode()); setDependencyCheck(originalAbd.getDependencyCheck()); setDependsOn(originalAbd.getDependsOn()); setAutowireCandidate(originalAbd.isAutowireCandidate()); setPrimary(originalAbd.isPrimary()); copyQualifiersFrom(originalAbd); setInstanceSupplier(originalAbd.getInstanceSupplier()); setNonPublicAccessAllowed(originalAbd.isNonPublicAccessAllowed()); setLenientConstructorResolution(originalAbd.isLenientConstructorResolution()); setInitMethodName(originalAbd.getInitMethodName()); setEnforceInitMethod(originalAbd.isEnforceInitMethod()); setDestroyMethodName(originalAbd.getDestroyMethodName()); setEnforceDestroyMethod(originalAbd.isEnforceDestroyMethod()); setSynthetic(originalAbd.isSynthetic()); setResource(originalAbd.getResource()); } else { setConstructorArgumentValues(new ConstructorArgumentValues(original.getConstructorArgumentValues())); setPropertyValues(new MutablePropertyValues(original.getPropertyValues())); setLazyInit(original.isLazyInit()); setResourceDescription(original.getResourceDescription()); } } 1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.到这里基本上可以肯定了,这个构造方法其实就是将给定的BeanDefinition参数做一个深度拷贝,生成一个新的BeanDefinition对象。算是完全验证了我们上面对MergedBeanDefinition生成过程的分析。
最后
另外还整理成了40多套PDF文档:全套的Java面试宝典手册,“性能调优+微服务架构+并发编程+开源框架+分布式”等七大面试专栏,包罗Tomcat、JVM、MySQL、SpringCloud、SpringBoot、Dubbo、并发、Spring、SpringMVC、MyBatis、Zookeeper、Ngnix、Kafka、MQ、Redis、MongoDB、memcached等等。如果你对这个感兴趣,小编可以免费分享。
资料获取方式:关注小编+转发文章+私信【面试题】获取上述资料~
重要的事情说三遍,转发+转发+转发,一定要记得转发哦!!!
|