《Spring系列》第7章 BeanDefinition
前言
BeanDefinition
是定义Bean配置元信息的接口,Spring会加载指定的Java类变成BeanDefinition对象, 然后根据此来创建Bean,那么下面就来详细介绍一下
1.类图
从类图中可以看出,BeanDefinition
继承了AttributeAccessor
和BeanMetadataElement
两个接口;
2.顶层接口
AttributeAccessor
public interface AttributeAccessor {void setAttribute(String name, @Nullable Object value);@NullableObject getAttribute(String name);@NullableObject removeAttribute(String name);boolean hasAttribute(String name);String[] attributeNames();
}
BeanDefinition
BeanDefinition
定义很多接口方法,对应Bean属性,通过这种方式定义,\\、代表子类必须提供这些属性
3.抽象父类
AbstractBeanDefinition
对这个接口进行了实现,它提供了一个BeanDefinition
所需要具备的基本能力,它是最终全能BeanDefinition
实现类的基类,下面展示了部分属性,对应的我们在bean中的各种属性
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessorimplements BeanDefinition, Cloneable {// 默认的SCOPE,默认是单例public static final String SCOPE_DEFAULT = "";// 不进行自动装配public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;// 根据Bean的名字进行自动装配,即autowired属性的值为bynamepublic static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;// 根据Bean的类型进行自动装配,调用setter函数装配属性,即autowired属性的值为byTypepublic static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;// 自动装配构造函数的形参,完成对应属性的自动装配,即autowired属性的值为byConstructorpublic static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;@Deprecatedpublic static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;// 不进行依赖检查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;//若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字public static final String INFER_METHOD = "(inferred)";// Bean的class对象或是类的全限定名@Nullableprivate volatile Object beanClass;//bean的作用范围,对应bean属性scope是单例@Nullableprivate String scope = SCOPE_DEFAULT;//是否是抽象,对应bean属性abstract 默认不为抽象类private boolean abstractFlag = false;//是否延迟加载,对应bean属性lazy-init@Nullableprivate Boolean lazyInit;// 默认不进行自动装配private int autowireMode = AUTOWIRE_NO;// 默认不进行依赖检查private int dependencyCheck = DEPENDENCY_CHECK_NONE;//用来表示一个bean的实例化依靠另一个bean先实例化//这里只会存放<bean/>标签的depends-on属性或是@DependsOn注解的值@Nullableprivate String[] dependsOn;//autowire-candidate属性设置为false,这样容器在查找自动装配对象时,//将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,//但是该bean本身还是可以使用自动装配来注入其他bean的private boolean autowireCandidate = true;//自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primaryprivate boolean primary = false;//用于记录Qualifier,对应子元素qualifierprivate final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();@Nullableprivate Supplier<?> instanceSupplier;//允许访问非公开的构造器和方法,程序设置private boolean nonPublicAccessAllowed = true;//是否以一种宽松的模式解析构造函数,默认为trueprivate boolean lenientConstructorResolution = true;//对应bean属性factory-bean 工厂类名@Nullableprivate String factoryBeanName;//对应bean属性factory-method 工厂方法名@Nullableprivate String factoryMethodName;//记录构造函数注入属性,对应bean属性constructor-arg@Nullableprivate ConstructorArgumentValues constructorArgumentValues;//普通属性集合@Nullableprivate MutablePropertyValues propertyValues;//方法重写的持有者,记录lookup-method、replaced-method元素private MethodOverrides methodOverrides = new MethodOverrides();//初始化方法,对应bean属性init-method@Nullableprivate String initMethodName;//销毁方法,对应bean属性destroy-method@Nullableprivate String destroyMethodName;//是否执行init-method,程序设置private boolean enforceInitMethod = true;//是否执行destroy-method,程序设置private boolean enforceDestroyMethod = true;//是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true,程序设置private boolean synthetic = false;//定义这个bean的应用,APPLICATION:用户,INFRASTRUCTURE:完全内部使用,与用户无关private int role = BeanDefinition.ROLE_APPLICATION;//bean的描述信息@Nullableprivate String description;//bean的资源@Nullableprivate Resource resource;
4.子类实现
分类介绍
继承自AbstractBeanDefinition
的全功能BeanDefinition实现类有 :
RootBeanDefinition
:Spring框架内部使用的,其他BeanDefinition都会转换为它GenericBeanDefinition
:编程定义使用的,官方推荐使用ChildBeanDefinition
:父子bean的时候使用,已逐步废弃ConfigurationClassBeanDefinition
:写在@Configuration
中的@Bean
,会被注册成该BeanDefinitionAnnotatedGenericBeanDefinition
:通过注解方式引入的Bean,最常见的是@Import
引入ScannedGenericBeanDefinition
:通过扫描方式引入的Bean,那就是@ComponentScan
RootBeanDefinition
- 从Spring2.5开始,
RootBeanDefinition
仅作为运行时的BeanDefinition视图。 - 如果编程定义BeanDefinition,那么推荐使用
GenericBeanDefinition
。GenericBeanDefinition
的优势在于,它允许动态定义父依赖项,而不是一个以”硬编码”定义BeanDefinition的角色。简单点说就是除了Spring框架,其它的编程都使用GenericBeanDefinition
,功能都一样,而且还有有优点 - Spring初始化时,会用
GenericBeanDefinition
或是ConfigurationClassBeanDefinition
(用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition。
上面的描述来自源码类注释,如下:
/* A root bean definition represents the merged bean definition that backs* a specific bean in a Spring BeanFactory at runtime. It might have been created* from multiple original bean definitions that inherit from each other,* typically registered as {@link GenericBeanDefinition GenericBeanDefinitions}.* A root bean definition is essentially the 'unified' bean definition view at runtime. <p>Root bean definitions may also be used for registering individual bean definitions* in the configuration phase. However, since Spring 2.5, the preferred way to register* bean definitions programmatically is the {@link GenericBeanDefinition} class.* GenericBeanDefinition has the advantage that it allows to dynamically define* parent dependencies, not 'hard-coding' the role as a root bean definition. @author Rod Johnson* @author Juergen Hoeller* @see GenericBeanDefinition* @see ChildBeanDefinition*/
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {//....
}
ChildBeanDefinition
基础介绍
当定义父子bean的时候,那么上面的RootBeanDefinition
可以作为一个普通的BeanDefinition
,也可以作为父bean,但是不能定义为子bean,那么这个时候就需要ChildBeanDefinition
,而且不可以单独存在,必须要依赖一个父BeanDetintiont
下面只展示该类中的部分代码,看到子类只是扩展了一个parentName
属性,存储父类
public class ChildBeanDefinition extends AbstractBeanDefinition {@Nullableprivate String parentName;// 省略构造方法
}
逐步废弃
Spring2.5之后废弃。
个人觉得废弃的原因有如下:
- 父子bean有必要条件:子bean必须有父bean中的全部属性,父bean必须为抽象类
- 再实际开发中,没有人愿意去维护这个东西,有时间维护这个还不如写几行代码
- 用这个的一般是使用XML定义bean的老系统,但现在都转到注解开发了
GenericBeanDefinition
基础介绍
通用的BeanDefinition
,它的出现是为了替换掉ChildBeanDefinition
,简单点说,之前为了实现父子bean,需要使用RootBeanDefinition
和ChildBeanDefinition
,现在单独使用GenericBeanDefinition
就可以实现
public class GenericBeanDefinition extends AbstractBeanDefinition {@Nullableprivate String parentName;// 省略构造方法...
}
测试用例
从网上拷贝下来的,只通过GenericBeanDefinition
实现父子bean
package com.xjm.bean.definition;import com.xjm.model.Child;
import com.xjm.model.Root;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class GenericBeanDefinitionDemo {// 获取父beanpublic static GenericBeanDefinition getRootBeanDefinition() {GenericBeanDefinition rootBeanDefinition = new GenericBeanDefinition();rootBeanDefinition.setBeanClass(Root.class);MutablePropertyValues propertyValues = new MutablePropertyValues();propertyValues.add("name", "root").add("description", "I am a rootBeanDefinition").add("isRoot", true);rootBeanDefinition.setPropertyValues(propertyValues);return rootBeanDefinition;}// 获取子beanpublic static GenericBeanDefinition getChildBeanDefinition() {GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();childBeanDefinition.setBeanClass(Child.class);MutablePropertyValues propertyValues = new MutablePropertyValues();propertyValues.add("parentName", "root");childBeanDefinition.setParentName("root");childBeanDefinition.setPropertyValues(propertyValues);return childBeanDefinition;}public static void main(String[] args) {// 1. 构建一个空的容器AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();GenericBeanDefinition rootBeanDefinition = getRootBeanDefinition();GenericBeanDefinition childBeanDefinition = getChildBeanDefinition();applicationContext.registerBeanDefinition("root", rootBeanDefinition);applicationContext.registerBeanDefinition("child", childBeanDefinition);applicationContext.refresh();Root root = applicationContext.getBean(Root.class);Child child = applicationContext.getBean(Child.class);System.out.println(root.toString());System.out.println(child.toString());}
}
ConfigurationClassBeanDefinition
基础介绍
- 通过
@Configuration + @Bean
- 在实际启动SpringBoot项目后,其实该
ConfigurationClassBeanDefinition
类型的BeanDefinition
非常多,大部分都是,原因:SpringBoot的自动化配置特点,会引入非常多的依赖,这些依赖注入自己的组件都是通过配置类的方式 - 这个bean创建是需要调用到Configuration Class中定义bean的方法。
- 如下源码所示,它是一个静态内部类,代码很少,扩展了2个属性:
annotationMetadata
和factoryMethodMetadata
。扩展的属性有啥用?下面介绍 factoryMethodMetadata
存储方法信息。用处:通过@Bean
定义的类,当获取时,就不是通过构造方法了,而是类似于工厂方法模式直接调用该方法,而且 如果@Bean
没有指定 Bean 的名字,默认会用方法的名字命名 Bean。那么factoryMethodMetadata
就存储方法的各种信息annotationMetadata
存储@Bean
注解属性。作用:@Bean
里面也有很多属性,创建的时候肯定需要用到
// 静态内部类
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {// 存储@Bean注解的信息private final AnnotationMetadata annotationMetadata;// 存储@Bean方法的信息private final MethodMetadata factoryMethodMetadata;// 省略...
}
Debug测试
编写了一个小测试,看到结果确实是对应类型
看到下图很多都是SpringBoot自动配置引入的Bean,基本都是ConfigurationClassBeanDefinition
AnnotatedGenericBeanDefinition
它用来定义通过注解引入的Bean,最常见的肯定就是@Import
引入
截图解释
下面截图解释:
- SpringBoot的启动类肯定是配置类,在启动的时候单独注入到容器,肯定是
AnnotatedGenericBeanDefinition
- 下图中的
aspectConfig
就变成了ScannedGenericBeanDefinition
,为啥呢?因为它不是单独注册的,它是启动类上的@ComponentScan
注解扫描到的配置类,所以就会是该类型 - 下图中的
qqqq
,这个就是正常的AnnotatedGenericBeanDefinition
,为啥呢?首先我把它和启动类分成不同层级的包,启动类扫描不到,然后再启动类上引入该配置类@Import(TestConfig.class)
,就会是想要的结果 - 当然是普通的Bean,通过该注解引入,也是是该类型
ScannedGenericBeanDefinition
通过名字可以看出是通过扫描的方式注入到Bean中,扫描需要是用到@ComponentScan
5.BeanDefinitionHolder
在扫描Bean的时候,会用到一个辅助类BeanDefinitionHolder
,顾名思义就是对BeanDefinition
的持有,通过包含其名称和别名
这个一般在解析@ComponentScan
的时候用到,会把扫描到的类封装成BeanDefinitionHolder
,把各种信息都存进去,就是一个辅助类很好理解
public class BeanDefinitionHolder implements BeanMetadataElement {private final BeanDefinition beanDefinition;// Bean名称private final String beanName;// 别名@Nullableprivate final String[] aliases;}
有,通过包含其名称和别名
这个一般在解析@ComponentScan
的时候用到,会把扫描到的类封装成BeanDefinitionHolder
,把各种信息都存进去,就是一个辅助类很好理解
public class BeanDefinitionHolder implements BeanMetadataElement {private final BeanDefinition beanDefinition;// Bean名称private final String beanName;// 别名@Nullableprivate final String[] aliases;}