一、简介
Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。
不管是是通过xml配置文件的 <Bean>
标签,还是通过注解配置的 @Bean
,它最终都会被解析成一个Bean定义信息(对象),最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。
BeanDefinition
作用是将不管任何形式定义的 Bean 转化为一个统一的格式,方便工厂后续的处理。
下面用一个非常形象的比喻,来形容Spring IoC容器和BeanDefinition之前的关系。
比喻:BeanFactory和BeanDefinition
Spring IoC容器比作一间餐馆,当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。
IoC容器也是一样,你只需要告诉它需要某个bean,它就把对应的实例(instance)扔给你,至于这个bean是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。
那么问题来了,作为餐馆,想要做出菜肴,得知道菜的原料和菜谱。同样地,IoC容器想要管理各个业务对象以及它们之间的依赖关系,需要通过某种途径来记录和管理这些信息。 BeanDefinition对象就承担了这个责任。
容器中的每一个bean都会有一个对应的BeanDefinition实例,该实例负责保存bean对象的 所有 必要信息,包括bean对象的class类型、是否是抽象类、构造方法和参数、其它属性等等
- 包限定的类名:通常,定义了 Bean 的实际实现类。
- Bean 行为配置元素,用于声明 Bean 在容器中的行为(作用域,生命周期回调等)。
- 引用其他 bean 进行其工作所需的 bean。这些引用也称为协作者或依赖项。
- 要在新创建的对象中设置的其他配置设置,例如,池的大小限制或在 Management 连接池的 bean 中使用的连接数。
简而言之,BeanDefinition
就是用来描述 Spring 应该如何创建指定的 Bean
BeanDefinitionRegistry
和 BeanFactory
就是这份菜谱,BeanDefinitionRegistry
抽象出bean的注册逻辑,而 BeanFactory
则抽象出了bean的管理逻辑,各个 BeanFactory
的实现类就具体承担了bean的注册以及管理工作。
DefaultListableBeanFactory
作为一个比较通用的 BeanFactory
实现,它同时也实现了BeanDefinitionRegistry
接口,因此它就承担了Bean的注册管理工作。
BeanDefinition
是容器对于bean配置的内部表示,Spring
将各个 bean
的 BeanDefinition
实例注册记录在 BeanDefinitionRegistry
中,该接口定义了对 BeanDefinition
的各种增删查操作,类似于内存数据库,其实现类 SimpleBeanDefinitionRegistry
主要以 Map 作为存储标的。
注:本篇文章使用的 SpringBoot 版本为 2.0.3.RELEASE,其 Spring 版本为 5.0.7.RELEASE
spring中的bean,在Java类的基础上增加了很多概念属性,比如scope(作用域),isLazyInit(是否延迟初始化),isSingleton(是否单例)等属性特征。spring就是根据BeanDefinition来实例化对应的bean。
处理BeanDefinition分为三个阶段:BeanDefinition的解析,注册,合并。
二、BeanDefinition继承体系
现如今,我们一般获取对象的方式有两种,一种是手动直接 new;另一种是交给 Spring 管理,Spring 将管理的对象称之为 Bean,容器会先实例化 Bean,然后自动注入,实例化的过程就需要依赖 BeanDefinition
。
BeanDefinition
用于保存 Bean 的相关信息,包括属性、构造方法参数、依赖的 Bean 名称及是否单例、延迟加载等,它是实例化 Bean 的原材料,Spring 就是根据 BeanDefinition
中的信息实例化 Bean。
1、父类
BeanDefinition
继承了 AttributeAccessor
和 BeanMetadataElement
(1)AttributeAccessor
定义了对对象元数据访问的抽象接口
注意:设置的是 BeanDefinition
的属性值,而不是设置生成的 bean 的属性值
public interface AttributeAccessor {
/**
* 为指定的属性设置值
*/
void setAttribute(String name, @Nullable Object value);
/**
* 获取指定属性的值
*/
@Nullable
Object getAttribute(String name);
/**
* 返回指定属性值,并移除该属性
*/
@Nullable
Object removeAttribute(String name);
/**
* 判断是否包含指定属性
*/
boolean hasAttribute(String name);
/**
* 返回所有的属性名
*/
String[] attributeNames();
}
AttributeAccessorSupport
是 AttributeAccessor
唯一抽象实现,内部基于 LinkedHashMap
实现了所有的接口,供其他子类继承使用 主要针对属性CRUD操作。
(2)BeanMetadataElement
具有访问source(配置源)的能力,这个方法在 @Configuration
中使用较多,因为它会被代理。
public interface BeanMetadataElement {
/**
* 返回元数据配置元
*/
@Nullable
default Object getSource() {
return null;
}
}
(3)实例代码
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName("com.suger.Rabbit");
//设置属性值
beanDefinition.setAttribute("name","tantan");
//将beanDefinition注册到spring容器中
context.registerBeanDefinition("rabbit",beanDefinition);
//加载或者刷新当前的配置信息,新加的BeanDifinition必须要在容器刷新之后才会创建bean
context.refresh();
//拿到所有的属性名
String[] attributes = context.getBeanDefinition("rabbit").attributeNames();
System.out.println(Arrays.toString(attributes));//[name]
//获取指定的属性值
String nameAttr = (String)context.getBeanDefinition("rabbit").getAttribute("name");
System.out.println(nameAttr);//tantan
// 获取配置源
Object soutce = context.getBeanDefinition("rabbit").getSource();
System.out.println(soutce);//null
//获取beanDefinition定义的bean对象
Rabbit rabbit = (Rabbit)context.getBean("rabbit");
//after refresh:Rabbit{name='null'}
System.out.println("after refresh:" + rabbit);
}
2、子类
BeanDefinition
是一个接口,它有多个实现类,这些实现类分别描述不同类型的 Bean。
AnnotatedBeanDefinition
:用于描述通过注解获得的 BeanAbstractBeanDefinition
:具体的、功能完备的BeanDefinition
类的基类,实现了大部分方法,实现了 是下面三个的父类:RootBeanDefinition
:最顶层父BeanDefinition
,不可有parent BeanDefinition
ChildBeanDefinition
:子BeanDefinition
,必须依赖一个RootBeanDefinition
GenericBeanDefinition
:Spring 2.5之后引入,即可作为父BeanDefinition
,又可作为子BeanDefinition
,编码时一般使用这个即可
三、BeanDefinition
一个 BeanDefinition
描述了一个 Bean 实例,实例包含属性值、构造方法参数值以及更多实现信息。该 BeanDefinition
只是是一个最小的接口,主要目的是允许修改属性值和其他 Bean 元数据,这里列出几个核心方法。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 单例Bean还是原型Bean(singleton/prototype)
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// Bean角色:用户定义的 Bean、来源于配置文件的 Bean、Spring 内部的 Bean
//指示BeanDefinition是应用程序的主要部分,通常对应于用户定义的bean。
int ROLE_APPLICATION = 0;
//指示BeanDefinition是一些较大配置的支持部分,通常是一个输出
int ROLE_SUPPORT = 1;
//表明BeanDefinition提供的是一个完全的后台角色,与最终用户无关。当注册完全属于ComponentDefinition内部工作的一部分的bean时,使用此提示。
int ROLE_INFRASTRUCTURE = 2;
// 设置、返回 Bean 的父类名称
void setParentName(@Nullable String parentName);
String getParentName();
// 设置、返回 Bean 的 className
void setBeanClassName(@Nullable String beanClassName);
String getBeanClassName();
// 设置、返回 Bean 的作用域
void setScope(@Nullable String scope);
String getScope();
// 设置、返回 Bean 是否懒加载
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 设置、返回当前 Bean 所依赖的其它 Bean 名称。
void setDependsOn(@Nullable String... dependsOn);
String[] getDependsOn();
// 设置、返回 Bean 是否可以自动注入。只对 @Autowired 注解有效
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 设置、返回当前 Bean 是否为主要候选 Bean 。
// 当同一个接口有多个实现类时,通过该属性来配置某个 Bean 为主候选 Bean。
void setPrimary(boolean primary);
boolean isPrimary();
// 设置、返回创建该 Bean 的工厂类。
void setFactoryBeanName(@Nullable String factoryBeanName);
String getFactoryBeanName();
// 设置、返回创建该 Bean 的工厂方法
void setFactoryMethodName(@Nullable String factoryMethodName);
String getFactoryMethodName();
// 返回该 Bean 构造方法参数值、所有属性
ConstructorArgumentValues getConstructorArgumentValues();
MutablePropertyValues getPropertyValues();
// 返回该 Bean 是否是单例、是否是非单例、是否是抽象的
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
// 返回 Bean 的类别。类别对应上面的三个属性值。
int getRole();
...
}
可以看到 BeanDefinition
接口提供了一系列操作 Bean 元数据的set、get方法,这些操作为 Bean 的描述定义了一套模板,具体的实现则交由子类。
1、AnnotatedBeanDefinition
AnnotatedBeanDefinition
是 BeanDefinition
子接口之一,该接口扩展了 BeanDefinition
的功能,其用来操作注解元数据。一般情况下,通过注解方式得到的 Bean(@Component
、@Bean
),其 BeanDefinition
类型都是该接口的实现类。
public interface AnnotatedBeanDefinition extends BeanDefinition {
// 获得当前 Bean 的注解元数据
AnnotationMetadata getMetadata();
// 获得当前 Bean 的工厂方法上的元数据
MethodMetadata getFactoryMethodMetadata();
}
该接口可以返回两个元数据的类:
AnnotationMetadata
:主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。MethodMetadata
:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。
2、AbstractBeanDefinition
具体的、功能完备的 BeanDefinition
类的基类,分解出 GenericBeanDefinition
、RootBeanDefinition
和 ChildBeanDefinition
的公共属性
AbstractBeanDefinition
是 BeanDefinition
的子抽象类,也是其他 BeanDefinition
类型的基类,其实现了接口中定义的一系列操作方法,并定义了一系列的常量属性,这些常量会直接影响到 Spring 实例化 Bean 时的策略。核心属性如下。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// 默认的 SCOPE,默认是单例
public static final String SCOPE_DEFAULT = "";
/* ---------------- 定义自动装配方式 -------------------*/
// 不进行自动装配
public static final int AUTOWIRE_NO =
AutowireCapableBeanFactory.AUTOWIRE_NO;
// 根据 Bean 的名字进行自动装配,byName
public static final int AUTOWIRE_BY_NAME =
AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
// 根据 Bean 的类型进行自动装配,byType
public static final int AUTOWIRE_BY_TYPE =
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
// 根据构造器进行自动装配
public static final int AUTOWIRE_CONSTRUCTOR =
AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
// 首先尝试按构造器自动装配。如果失败,再尝试使用 byType 进行自动装配。(Spring 3.0 之后已废除)
public static final int AUTOWIRE_AUTODETECT =
AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
/*---通过依赖检查来查看 Bean 的每个属性是否都设置完成,默认不进行依赖检查---*/
//不检查
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的销毁方法的名字,目前来说,推断的销毁方法的名字一般为close或是shutdown
//(即未指定Bean的销毁方法,但是内部定义了名为close或是shutdown的方法,则容器推断其为销毁方法)
public static final String INFER_METHOD = "(inferred)";
/*---------属性:基本囊括了Bean实例化需要的所有信息---------------*/
// 存放 Bean 的 Class 对象
private volatile Object beanClass;
// Bean 的作用范围
private String scope = SCOPE_DEFAULT;
// 非抽象
private boolean abstractFlag = false;
// 非延迟加载
private boolean lazyInit = false;
// 默认不自动装配
private int autowireMode = AUTOWIRE_NO;
// 默认不依赖检查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
// 依赖的 Bean 列表
private String[] dependsOn;
// 可以作为自动装配的候选者,意味着可以自动装配到其他 Bean 的某个属性中
private boolean autowireCandidate = true;
// 默认不是首选的
private boolean primary = false;
// 创建当前 Bean 实例工厂类名称
private String factoryBeanName;
// 创建当前 Bean 实例工厂类中方法名称
private String factoryMethodName;
// 存储构造方法的参数
private ConstructorArgumentValues constructorArgumentValues;
// 存储 Bean 属性名称以及对应的值
private MutablePropertyValues propertyValues;
// 存储被覆盖的方法信息
private MethodOverrides methodOverrides;
// init、destroy 方法名称
private String initMethodName;
private String destroyMethodName;
// 是否执行 init 和 destroy 方法
private boolean enforceInitMethod = true;
private boolean enforceDestroyMethod = true;
// Bean 是否是用户定义的而不是应用程序本身定义的
private boolean synthetic = false;
// Bean 的身份类别,默认是用户定义的 Bean
private int role = BeanDefinition.ROLE_APPLICATION;
// Bean 的描述信息
private String description;
// Bean 定义的资源
private Resource resource;
...
}
以上是 AbstractBeanDefinition
中定义的一些常量和属性,该类中还有一部分是操作这些属性的 set 和 get 方法,这些方法都由子类来操作,且应用程序中真正使用的也是这些子类 BeanDefinition。
先来看 AbstractBeanDefinition
直接实现类:RootBeanDefinition
、GenericBeanDefinition
、ChildBeanDefinition
。
(1)RootBeanDefinition
该类继承自 AbstractBeanDefinition
,他表示一个顶层的 BeanDefinition
,无法对其调用 setParentName
设置其 parent
, 它可以单独作为一个 BeanDefinition
,也可以作为其他 BeanDefinition
的父类。
一个RootBeanDefinition
定义表明它是一个可合并的 bean definition
:即在spring beanFactory
运行期间,可以返回一个特定的bean。但在Spring2.5以后,我们绝大多数情况还是可以使用 GenericBeanDefinition
来做。
子类Bean定义它所引用它的父类Bean。这时前面的class属性失效。子类Bean会继承父类Bean的所有属性,子类Bean也可以覆盖父类Bean的属性
我们非常熟悉的
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
这句代码,就是去合并parent的属性进来,这样体现了继承的强大。属性也才完整。
RootBeanDefinition
在 AbstractBeanDefinition
的基础上定义了更多属性。
public class RootBeanDefinition extends AbstractBeanDefinition {
// BeanDefinitionHolder 存储 Bean 的名称、别名、BeanDefinition
private BeanDefinitionHolder decoratedDefinition;
// AnnotatedElement 是java反射包的接口,通过它可以查看 Bean 的注解信息
private AnnotatedElement qualifiedElement;
// 允许缓存
boolean allowCaching = true;
// 工厂方法是否唯一
boolean isFactoryMethodUnique = false;
// 封装了 java.lang.reflect.Type,提供了泛型相关的操作
volatile ResolvableType targetType;
// 缓存 Class,表示 RootBeanDefinition 存储哪个类的信息
volatile Class<?> resolvedTargetType;
// 缓存工厂方法的返回类型
volatile ResolvableType factoryMethodReturnType;
// 这是以下四个构造方法字段的通用锁
final Object constructorArgumentLock = new Object();
// 用于缓存已解析的构造方法或工厂方法
Executable resolvedConstructorOrFactoryMethod;
// 将构造方法参数标记为已解析
boolean constructorArgumentsResolved = false;
// 用于缓存完全解析的构造方法参数
Object[] resolvedConstructorArguments;
// 缓存待解析的构造方法参数
Object[] preparedConstructorArguments;
// 这是以下两个后处理字段的通用锁
final Object postProcessingLock = new Object();
// 表明是否被 MergedBeanDefinitionPostProcessor 处理过
boolean postProcessed = false;
// 在生成代理的时候会使用,表明是否已经生成代理
volatile Boolean beforeInstantiationResolved;
// 实际缓存的类型是 Constructor、Field、Method 类型
private Set<Member> externallyManagedConfigMembers;
// InitializingBean中 的 init 回调函数名 afterPropertiesSet 会在这里记录,以便进行生命周期回调
private Set<String> externallyManagedInitMethods;
// DisposableBean 的 destroy 回调函数名 destroy 会在这里记录,以便进生命周期回调
private Set<String> externallyManagedDestroyMethods;
...
}
(2)ChildBeanDefinition
该类继承自 AbstractBeanDefinition
。其相当于一个子类,不可以单独存在,必须依赖一个 RootBeanDetintion
,构造 ChildBeanDefinition
时,通过构造方法传入父 BeanDetintion
的名称或通过 setParentName
设置父名称。它可以从父类继承方法参数、属性值,并可以重写父类的方法,同时也可以增加新的属性或者方法。若重新定义 init 方法,destroy 方法或者静态工厂方法,ChildBeanDefinition
会重写父类的设置。
从 Spring 2.5 开始,以编程方式注册 Bean 定义的首选方法是 GenericBeanDefinition,GenericBeanDefinition 可以有效替代 ChildBeanDefinition 的绝大分部使用场合。
(3)GenericBeanDefinition
标准bean definition,通用的
GenericBeanDefinition
是 Spring 2.5 以后新引入的 BeanDefinition
,是 ChildBeanDefinition
更好的替代者,它同样可以通过 setParentName
方法设置父 BeanDefinition
。
除了具有指定类、可选的构造参数值和属性参数这些其它bean definition
一样的特性外,它还具有通过parenetName
属性来灵活(动态)设置parent bean definition
,而非硬编码作为rootBeanDefinition
。
备注:若你是xml配置,最初被加载进来都是一个GenericBeanDefinition
,之后再逐渐解析的。
public class GenericBeanDefinition extends AbstractBeanDefinition {
@Nullable
private String parentName;
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
@Override
@Nullable
public String getParentName() {
return this.parentName;
}
}
使用案例代码
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(RootConfig.class);
// 向工厂里注册Bean信息
GenericBeanDefinition parentBeanDef = new GenericBeanDefinition();
parentBeanDef.setBeanClass(Parent.class);
parentBeanDef.setBeanClassName(Parent.class.getName());
parentBeanDef.setScope(BeanDefinition.SCOPE_SINGLETON);
// 就这样,我们可以动态的给子Bean 设置一个父Bean进去
GenericBeanDefinition childBeanDef = new GenericBeanDefinition();
childBeanDef.setParentName(parentBeanDef.getBeanClassName());
childBeanDef.setBeanClass(Child.class);
applicationContext.registerBeanDefinition("parent", parentBeanDef);
applicationContext.registerBeanDefinition("child", childBeanDef);
System.out.println(applicationContext.getBeanDefinition("parent"));
System.out.println(applicationContext.getBeanDefinition("child"));
}
(4)BeanDefinition的合并
merged bean definition
它不是一个具体的类,而是 Spring 对 BeanDefinition 进行的一种合并操作。
在根据 BeanDefinition
创建 bean 的实例之前,会通过AbstractBeanFactory#getMergedLocalBeanDefinition()
来将 child 和 parent bean definition
进行合并。
BeanDefinition 的 merge 操作的作用是什么?
答:对 BeanDefinition 进行 merge 操作时,会将 child 的属性与 parent 的属性进行合并,当有相同属性时,以 child 的为准。
而类似 propertyValues、constructor args 这种集合类的参数属性的话,就会取并集。
3、上面2个的共同子类
https://www.cnblogs.com/xfeiyun/p/15666295.html
区别
ScannedGenericBeanDefinition
和AnnotatedGenericBeanDefinition
其实功能上是等价的,都是基于注解,区别在于:AnnotatedGenericBeanDefinition
只能用于已经被注册或被扫描到的类
ScannedGenericBeanDefinition
ScannedGenericBeanDefinition
该类继承自 GenericBeanDefinition
,并实现了 AnnotatedBeanDefinition
接口。用来描述@Component
、@Service
、@Controller
等注解注释的bean
这个类不会提前加载bean类。而是从“.class”文件本身检索所有相关的元数据,用ASM ClassReader解析。它在功能上等价于
AnnotatedGenericBeanDefinition # AnnotatedGenericBeanDefinition (AnnotationMetadata)
但是通过已扫描的bean与已通过其他方式注册或检测的bean的类型进行区分。
它的源码很简单,就是多了一个属性:private final AnnotationMetadata metadata
用来存储扫描进来的Bean的一些注解信息。
public class ScannedGenericBeanDefinition extends GenericBeanDefinition
implements AnnotatedBeanDefinition {
/**
* 当前 bean 的注解元数据
*/
private final AnnotationMetadata metadata;
// 它只有一个构造函数:必须传入MetadataReader
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
}
...
}
AnnotatedGenericBeanDefinition
在基于注解驱动的Spring应用着,它使用得非常的多。因为获取注解信息非常的方便~
该类继承自 GenericBeanDefinition
,并实现了 AnnotatedBeanDefinition
接口。
AnnotatedGenericBeanDefinition只能用于已经被注册或被扫描到的类(否则你手动new一个,它就不在容器里了,那就脱离管理了)
这个 GenericBeanDefinition
变体主要用于测试期望操作 AnnotatedBeanDefinition
的代码,例如Spring组件扫描支持中的策略实现(其中默认定义类是 ScannedGenericBeanDefinition
},它也实现了 AnnotatedBeanDefinition
接口)。
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition
implements AnnotatedBeanDefinition {
/**
* 当前 bean 的注解元数据
*/
private final AnnotationMetadata metadata;
/**
* 储工厂方法的元数据
*/
@Nullable
private MethodMetadata factoryMethodMetadata;
/**
* 根据给定的 bean class 创建AnnotatedGenericBeanDefinition
* @param beanClass the loaded bean class (已经加载的bean class)
*/
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = AnnotationMetadata.introspect(beanClass);
}
/**
* 为给定的注释元数据创建一个新的AnnotatedGenericBeanDefinition,
* 允许基于asm的处理并避免bean类的早期加载。
* 注意,此构造函数在功能上等价于ScannedGenericBeanDefinition,
* 但是后者的语义表明,bean是专门通过组件扫描发现的,而不是通过其他方法。
*/
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
...
}
使用案例
AnnotatedBeanDefinition beanDefinition =
new AnnotatedGenericBeanDefinition(RootConfig.class);
// 就这么一下子,就把注解们都拿到了,简直不要太方便,简直可以当工具类来用
Set<String> annotationTypes = beanDefinition.getMetadata().getAnnotationTypes();
//[org.springframework.context.annotation.ComponentScan, org.springframework.context.annotation.Configuration]
System.out.println(annotationTypes);
System.out.println(beanDefinition.isSingleton()); //true
System.out.println(beanDefinition.getBeanClassName()); //com.config.RootConfig
ConfigurationClassBeanDefinition
首先需要注意的是,它是 ConfigurationClassBeanDefinitionReader
的一个私有的静态内部类:这个类负责将 @Bean
注解的方法转换为对应的 ConfigurationClassBeanDefinition
类(非常的重要)
该内部类继承自 RootBeanDefinition
,并实现了 AnnotatedBeanDefinition
接口。这个 BeanDefinition
用来描述在标注 @Configuration
注解的类中,通过 @Bean
注解实例化的 Bean。
其功能特点如下:
1、如果
@Bean
注解没有指定Bean
的名字,默认会用方法的名字命名Bean
。2、标注
@Configuration
注解的类会成为一个工厂类,而标注@Bean
注解的方法会成为工厂方法,通过工厂方法实例化Bean
,而不是直接通过构造方法初始化。3、标注
@Bean
注解的类会使用构造方法自动装配(这里说的是类,第二点说的是方法)
Spring
初始化时,会用 GenericBeanDefinition
或是 ConfigurationClassBeanDefinition
(用 @Bean
注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition
。
四、BeanDefinitionBuilder
BeanDefinitionBuilder
:工具类,作用是快速创建一个BeanDefinition
使用它的好处是,可以进行方法的连缀。
没有特殊指明,创建的都是GenericBeanDefinition,源码非常的简单
public final class BeanDefinitionBuilder {
/** -------- 各种获取BeanDefinitionBuilder的静态方法 -------------- */
public static BeanDefinitionBuilder genericBeanDefinition() {
return new BeanDefinitionBuilder(new GenericBeanDefinition());
}
public static BeanDefinitionBuilder genericBeanDefinition(String beanClassName) {
BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
builder.beanDefinition.setBeanClassName(beanClassName);
return builder;
}
public static BeanDefinitionBuilder genericBeanDefinition(Class<?> beanClass) {
BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
builder.beanDefinition.setBeanClass(beanClass);
return builder;
}
public static <T> BeanDefinitionBuilder genericBeanDefinition(Class<T> beanClass, Supplier<T> instanceSupplier) {
BeanDefinitionBuilder builder = new BeanDefinitionBuilder(new GenericBeanDefinition());
builder.beanDefinition.setBeanClass(beanClass);
builder.beanDefinition.setInstanceSupplier(instanceSupplier);
return builder;
}
//...
}
使用案例
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Child.class)
.setRole(BeanDefinition.ROLE_APPLICATION)
.setScope(BeanDefinition.SCOPE_SINGLETON)
.addPropertyValue("name", "hare")
.setLazyInit(false)
//Spring5.0后提供的,可以自己书写函数,在里面做任意事情
//bdf是个AbstractBeanDefinition
.applyCustomizers((bdf) -> {
AbstractBeanDefinition abdf = (AbstractBeanDefinition) bdf;
abdf.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_NO);
}).getRawBeanDefinition();
System.out.println(beanDefinition); //Generic bean: class [com.fsx.maintest.Child]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; d...
五、BeanDefinitionReader
1、接口介绍
BeanDefinitionReader
:该接口的作用就是加载和注册 Bean
BeanDefinitionReader
可以将XML、注解等形式的bean配置信息解析读取进来,将其转换为 IoC 容器内部的数据结构:BeanDefinition。
在 Spring 中,Bean 一般来说都在配置文件中定义。而在配置的路径由在 web.xml 中定义(还有全注解的方式)。所以加载 Bean 的步骤大致就是:
- 加载资源,通过配置文件的路径(Location)加载配置文件(Resource)
- 解析资源,通过解析配置文件的内容得到 Bean。
public interface BeanDefinitionReader {
/**
* 返回 bean factory ,可用与注册 beanDefinition
* 工厂是通过BeanDefinitionRegistry接口公开的,它封装了与bean定义处理相关的方法。
* 注:大多数具体的 beanFactory 都实现了 BeanDefinitionRegistry
*/
BeanDefinitionRegistry getRegistry();
// 返回用于加载资源的 ResourceLoader(可以为null)
@Nullable
ResourceLoader getResourceLoader();
// 加载Bean的类加载器
@Nullable
ClassLoader getBeanClassLoader();
// 生成Bean名称的名字生成器(若没有指定名称的话,会调用它生成)
BeanNameGenerator getBeanNameGenerator();
// 核心方法,loadbean定义进来,然后注册到上面的register 里面去
int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}
2、继承体系
AbstractBeanDefinitionReader
:是一个抽象类,同时实现了EnvironmentCapable
接口,提供环境的get和set方法。它实现了BeanDefinitionReader
的一些通用方法,比如按照路径来读取Bean定义信息的方法→int loadBeanDefinitions(String location)
。对于更为具体的方法,比如根据资源来读取Bean定义信息的方法→int loadBeanDefinitions(Resource resource)
,则交由子类来实现。
PropertiesBeanDefinitionReader:是一个具体实现类,可以从properties文件读取Bean定义信息。
XmlBeanDefinitionReader:具体实现类,可以从XML文件读取Bean定义信息。
GroovyBeanDefinitionReader:具体实现类,可以读取Groovy 语言写的Bean的定义信息。
其他的 BeanDefinitionReader
- AnnotatedBeanDefinitionReader , 并不是 BeanDefinitionReader 的实现类,它没有继承任何类。在AnnotationConfigApplicationContext中使用到,AnnotatedBeanDefinitionReader 的构造方法中参数为BeanDefinitionRegistry。它的重要方法是register,用于获取一个或多个带有注解的具体类,之后将他们解析为BeanDefintion,之后注册到Registry中。
3、AbstractBeanDefinitionReader
它实现了一些基本的方法,但是核心方法 loadBeanDefinitions
是交给子类实现
public abstract class AbstractBeanDefinitionReader
implements EnvironmentCapable, BeanDefinitionReader {
private final BeanDefinitionRegistry registry;
@Nullable
private ResourceLoader resourceLoader;
@Nullable
private ClassLoader beanClassLoader;
// 会有环境变量
private Environment environment;
// 默认的名字生成器(类名首字母小写)
private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();
/*
* 根据给定的 beanFactory 创建一个 AbstractBeanDefinitionReader。
* 如果传入的 beanFactory 不仅实现了 BeanDefinitionRegistry ,还实现了 ResourceLoader 接口,
* 那么它也将被用作默认的ResourceLoader。这通常是ApplicationContext实现的情况。
*
* 如果给定一个普通的BeanDefinitionRegistry,默认的ResourceLoader将是一个PathMatchingResourcePatternResolver。
*
* 如果给定的 beanFactory 也实现了 EnvironmentCapable,那么它的环境将被这个reader使用。
* 否则,reader将初始化并使用StandardEnvironment。
* 所有的ApplicationContext都是实现了EnvironmentCapable的,而普通的BeanFactory实现不是。
*/
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// Determine ResourceLoader to use.
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
} else {
// 注意这个处理
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
// 如果注册器里有环境变量,就用它的 否则new一个标准的,它下面也提供了set方法可以设置
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
} else {
this.environment = new StandardEnvironment();
}
}
...
}
4、XmlBeanDefinitionReader
XmlBeanDefinitionReader
:从xml中加载Bean定义信息
我们注解配置中@Configuration上也可以加上@ImportResource导入外置的xml配置文件。它由此方法ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromImportedResources处理,内部借助的就是XmlBeanDefinitionReader去解析它的
5、PropertiesBeanDefinitionReader
PropertiesBeanDefinitionReader
:直接从properties文件或者Map里加载Bean
六、BeanDefinitionRegistry
保存bean定义的注册中心接口,例如 RootBeanDefinition
和 childBeandefinition
实例。通常由beanfactory
实现内部工作与抽象定义层次结构
这是Spring's bean factory packages
中封装bean定义注册的唯一接口。标准BeanFactory接口只涵盖对完全配置的工厂实例的访问
Spring core
中实现该接口的有:
DefaultListableBeanFactory
GenericApplicationContext
。
1、接口源码
public interface BeanDefinitionRegistry extends AliasRegistry {
//注册 BeanDefinition
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
//删除 BeanDefinition
void removeBeanDefinition(String beanName);
//获取 BeanDefinition
BeanDefinition getBeanDefinition(String beanName);
//判断该容器中是否包含指定的 BeanDefinition
boolean containsBeanDefinition(String beanName);
//获取该容器所有的 BeanDefinition
String[] getBeanDefinitionNames();
//获取该容器所有的 BeanDefinition 数量
int getBeanDefinitionCount();
//确定给定的bean名称是否已经在此注册中心中使用,
//例如,是否有一个本地bean或别名在这个名称下注册。
boolean isBeanNameInUse(String beanName);
}
2、DefaultListableBeanFactory实现
(1)registerBeanDefinition
注册的核心就是 this.beanDefinitionMap.put(beanName, beanDefinition);
bean定义的注册过程,其实就是把Bean定义,put进 beanDefinitionMap
中;另外在 beanDefinitionNames
的 Set<String>
中放入一个 bean name
缓存起来,表示标记bean name对应的Bean定义已解析
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory,
BeanDefinitionRegistry,
Serializable {
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
//1、判断beanDefinition类型,如果是则要校验此bean定义。
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
//校验此bean定义。
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 2、获取容器中指定名称的BeanDefinition
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
// 3、如果容器中已有指定名称的BeanDefinition
if (existingDefinition != null) {
//判断是否允许重写BeanDefinition,如果不允许,则直接报错
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
//使用传入的 beanDefinition 替换原来的
this.beanDefinitionMap.put(beanName, beanDefinition);
}
// 3、如果容器中不含有指定名称的BeanDefinition
else {
//检查工厂的bean创建阶段是否已经开始,即是否有任何bean被标记为在此期间创建。
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
// 不能再修改启动时集合元素(对于稳定迭代),防止出现集合List<String> beanDefinitionNames线程安全问题
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
//更新容器的内部手动添加的单例集合manualSingletonNames
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
//还在启动注册阶段
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
//更新容器的内部手动添加的单例集合manualSingletonNames
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
//重置所有指定beanName的BeanDefinition相关的缓存
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
}
七、不存在BeanDefinition的情况
需要说明的一点是:加入你是自己直接通过SingletonBeanRegistry#registerSingleton
向容器手动注入Bean的,那么就不会存在这份Bean定义信息的,这点需要注意。
Spring内部有不少这样的例子(因为这种Bean非常简单,根本不需要定义信息):
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME, Collections.unmodifiableMap(attributeMap));
那我们注解的@Bean以及@Component的这么些bean定义都是谁去加载的呢? 需要注意的是这个就不属于它了。
@Bean都是@Configuration配置类里,统一由ConfigurationClassParser#parse()里去处理的(直接执行Method就行)
@Component这种组件统一由解析@ComponentScan的处理器的ComponentScanAnnotationParser(借助ClassPathBeanDefinitionScanner) 。参考文章:
Spring解析@ComponentScan注解分析(ComponentScanAnnotationParser、ClassPathBeanDefinitionScanner)