抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

SpringIOC-BeanDefinition介绍

什么是BeanDefinition

​ 在Java中,一切皆对象。在JDK中使用java.lang.Class来描述这个对象。

​ 用过spring的人都知道,我们将对象注入到spring容器中,交给spring来帮我们管理。这种对象我们称之为bean对象。但是这些bean对象在spring容器中,到底是以什么形式存在,具有哪些属性、行为呢?今天我们进入到spring源码来一探究竟。

​ 在Spring中,存在bean这样一个概念,那Spring又是怎么抽象bean这个概念,用什么类来描述bean这个对象呢?Spring使用BeanDefinition来描述bean

BeanDefinition 的作用

​ 在前面分析Spring IoC容器的时候,贯穿全文的一个概念:Bean定义信息。它是Spring容器的一个核心概念,那么本文就深入分析一下BeanDefinition这个接口(类)。

Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构

​ 不管是是通过xml配置文件的<bean>标签,还是通过注解配置的@Bean,还是通扫描的@Component,它最终都会被解析成一个Bean定义信息(对象),最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作

​ 从上可知BeanDefinition这个接口对Spring IoC容器的重要之处,所以了解好了它(以及子类),能让我们更大视野的来看Spring管理Bean的一个过程,也能透过现象看本质。

BeanFactory和BeanDefinition

​ Spring IoC容器比作一间餐馆,当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。
​ IoC容器也是一样,你只需要告诉它需要某个bean,它就把对应的实例(instance)扔给你,至于这个bean是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。

​ 那么问题来了,作为餐馆,想要做出菜肴,得知道菜的原料和菜谱。同样地,IoC容器想要管理各个业务对象以及它们之间的依赖关系,需要通过某种途径来记录和管理这些信息。 BeanDefinition对象就承担了这个责任

​ 容器中的每一个bean都会有一个对应的BeanDefinition实例,该实例负责保存bean对象的 所有 必要信息,包括bean对象的class类型、是否是抽象类、构造方法和参数、其它属性等等(所以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));

现在可以开始做菜了吗?其实还不行,因为还没有菜谱(不知道做什么菜,怎么做~)
BeanDefinitionRegistry和 BeanFactory就是这份菜谱,BeanDefinitionRegistry抽象出bean的注册逻辑,而BeanFactory则抽象出了bean的管理逻辑
各个BeanFactory的实现类就具体承担了bean的注册以及管理工作

DefaultListableBeanFactory作为一个比较通用的BeanFactory实现,它同时也实现了BeanDefinitionRegistry接口,因此它就承担了Bean的注册管理工作

最后我们总结一下比喻关系:

  • Spring IoC容器:餐馆(服务员)
  • BeanDefinitionRegistry和 BeanFactory:菜谱
  • BeanDefinitionRegistry:抽象出来的,向菜谱里注册菜(的管理器)
  • BeanFactory:抽象出来的,管理这些菜谱(的管理器)
  • BeanDefinition:原料(做菜所需要的原料)
  • DefaultListableBeanFactory:具体实施者(具体注册菜谱、做菜的实施者)
    依赖注入的使用者:客户(进店吃饭的人)

BeanDefinition 的属性

属性 行为 解释
parentName String getParentName(); void setParentName(@Nullable String parentName); bean定义对象的父类定义对象名称
beanClassName String getBeanClassName(); void setBeanClassName(@Nullable String beanClassName); bean对象的实际class类
scope String getScope(); void setScope(@Nullable String scope); bean对象是否为单例<singleton或者prototype>
lazyInit boolean isLazyInit(); void setLazyInit(boolean lazyInit); 是否懒加载
dependsOn String[] getDependsOn(); void setDependsOn(@Nullable String… dependsOn); 设置依赖的bean对象,被依赖的bean对象总是会比当前bean对象先创建
autowireCandidate boolean isAutowireCandidate(); void setAutowireCandidate(boolean autowireCandidate); 设置是否可以自动注入。只对@Autowired注解有效,配置文件中可以通过property显示注入
primary boolean isPrimary(); void setPrimary(boolean primary); 配置bean为主要候选bean。当同一个接口的多个实现类或者一个类多次注入到spring容器时,通过该属性来配置某个bean为主候选bean,通过类型来注入时,默认为使用主候选bean注入
factoryBeanName String getFactoryBeanName(); void setFactoryBeanName(@Nullable String factoryBeanName); 设置创建bean的工厂名称
factoryMethodName String getFactoryMethodName(); void setFactoryMethodName(@Nullable String factoryMethodName); 设置创建bean的工厂中,创建bean的具体方法
initMethodName String getInitMethodName(); void setInitMethodName(@Nullable String initMethodName); 设置创建bean时,默认初始化的方法
destroyMethodName String getDestroyMethodName(); void setDestroyMethodName(@Nullable String destroyMethodName); 设置销毁bean时调用的方法名称。注意需要调用context的close()方法才会调用
role int getRole(); void setRole(int role); 设置bean的分类
description String getDescription(); void setDescription(@Nullable String description); 对bean对象的描述

BeanDefinition 的继承关系

BeanDefinition的实现类

ChildBeanDefinition

ChildBeanDefinition是一种bean definition,它可以继承它父类的设置,即ChildBeanDefinition对RootBeanDefinition有一定的依赖关系。

​ ChildBeanDefinition从父类继承构造参数值,属性值并可以重写父类的方法,同时也可以增加新的属性或者方法。(类同于java类的继承关系)。若指定初始化方法,销毁方法或者静态工厂方法,ChildBeanDefinition将重写相应父类的设置。depends on,autowire mode,dependency check,sigleton,lazy init 一般由子类自行设定。

GenericBeanDefinition

​ 注意:从spring 2.5 开始,提供了一个更好的注册bean definition类GenericBeanDefinition,它支持动态定义父依赖,方法是GenericBeanDefinition.setParentName(java.lang.String),GenericBeanDefinition可以有效的替代ChildBeanDefinition的绝大分部使用场合。

​ GenericBeanDefinition是一站式的标准bean definition,除了具有指定类、可选的构造参数值和属性参数这些其它bean definition一样的特性外,它还具有通过parenetName属性来灵活设置parent bean definition。

​ 通常, GenericBeanDefinition用来注册用户可见的bean definition(可见的bean definition意味着可以在该类bean definition上定义post-processor来对bean进行操作,甚至为配置parent name做扩展准备)。RootBeanDefinition / ChildBeanDefinition用来预定义具有parent/child关系的bean definition。

RootBeanDefinition

​ 一个RootBeanDefinition定义表明它是一个可合并的bean definition:即在spring beanFactory运行期间,可以返回一个特定的bean。RootBeanDefinition可以作为一个重要的通用的bean definition 视图。

​ RootBeanDefinition用来在配置阶段进行注册bean definition。然后,从spring 2.5后,编写注册bean definition有了更好的的方法:GenericBeanDefinition。GenericBeanDefinition支持动态定义父类依赖,而非硬编码作为root bean definition。

源码分析

因为它继承了AttributeAccessor,和BeanMetadataElement,所以我们先有必要来了解下这两个接口:

AttributeAccessor

定义了对对象元数据访问的抽象接口

1
2
3
4
5
6
7
8
9
10
11
12
// 接口都比较简单  就是定义了对对象属性的一些访问方法
//说明它可以持有Bean元数据元素,作用是可以持有XML文件的一个bean标签对应的Object(或者@Configuration元配置对象)
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是唯一抽象实现,内部基于LinkedHashMap实现了所有的接口,供其他子类继承使用 主要针对属性CRUD操作

BeanMetadataElement

具有访问source(配置源)的能力,这个方法在@Configuration中使用较多,因为它会被代理

1
2
3
4
5
6
7
8
9
10
11
//接口提供了一个getResource()方法,用来传输一个可配置的源对象。
public interface BeanMetadataElement {

/**
* Return the configuration source {@code Object} for this metadata element
* (may be {@code null}).
* 返回元数据元素配置元对象
*/
@Nullable
Object getSource();
}
BeanDefinition

定义了Bean的各种信息

一个BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息。

BeanDefinition仅仅是一个最简单的接口,主要功能是允许BeanFactoryPostProcessor
例如PropertyPlaceHolderConfigure 能够检索并修改属性值和别的bean的元数据

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
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

// 单例Bean还是原型Bean
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

// Bean角色
int ROLE_APPLICATION = 0; //应用程序重要组成部分
int ROLE_SUPPORT = 1; //做为大量配置的一部分(支持、扩展类) 实际上就是说,我这个Bean是用户的,是从配置文件中过来的。
int ROLE_INFRASTRUCTURE = 2; //指内部工作的基础构造 实际上是说我这Bean是Spring自己的,和你用户没有一毛钱关系


// Modifiable attributes
//parent definition(若存在父类的话,就设置进去)
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();

// 指定Class类型。需要注意的是该类型还有可能被改变在Bean post-processing阶段
// 若是getFactoryBeanName getFactoryMethodName这种情况下会改变
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();

//SCOPE_SINGLETON或者SCOPE_PROTOTYPE两种
void setScope(@Nullable String scope);
@Nullable
String getScope();

// @Lazy 是否需要懒加载(默认都是立马加载的)
void setLazyInit(boolean lazyInit);
boolean isLazyInit();

// 此Bean定义需要依赖的Bean(显然可以有多个)
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();

// 这个Bean是否允许被自动注入到别的地方去(默认都是被允许的)
// 注意:此标志只影响按类型装配,不影响byName的注入方式的~~~~
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();

// 是否是首选的 @Primary
void setPrimary(boolean primary);
boolean isPrimary();

// 指定使用的工厂Bean(若存在)的名称~
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
//指定工厂方法~
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();

// 获取此Bean的构造函数参数值们 ConstructorArgumentValues:持有构造函数们的
// 绝大多数情况下是空对象 new ConstructorArgumentValues出来的一个对象
// 当我们Scan实例化Bean的时候,可能用到它的非空构造,这里就会有对应的值了,然后后面就会再依赖注入了
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}

// 获取普通属性集合~~~~
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}

// Read-only attributes
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();

// 对应上面的role的值
int getRole();
//@Description
@Nullable
String getDescription();
// 返回该Bean定义来自于的资源的描述(用于在出现错误时显示上下文)
@Nullable
String getResourceDescription();
//返回原始BeanDefinition,如果没有则返回@null
// 若这个Bean定义被代理、修饰过 这个方法可以返回原始的
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}

抽象实现、实现类们。上面已经画出了一些类的结构图,下面一个个来看

AnnotatedBeanDefinition

AnnotationMetadata定义了访问特定类的注解的抽象接口,它不需要加载该类即可访问

1
2
3
4
5
6
7
8
9
public interface AnnotatedBeanDefinition extends BeanDefinition {
//获取该bean definition的注解元数据
AnnotationMetadata getMetadata();

//@since 4.1.1
//Obtain metadata for this bean definition's factory method(如果不存在就返回null)
@Nullable
MethodMetadata getFactoryMethodMetadata();
}

该注解Bean定义旗下三大实现类:ScannedGenericBeanDefinition,ConfigurationClassBeanDefinition,AnnotatedGenericBeanDefinition

AbstractBeanDefinition

AbstractBeanDefinition实现了BeanDefinition定义的一系列操作,定义了描述Bean画像的一系列属性,在AbstractBeanDefinition的基础上,Spring衍生出了一系列具有特殊用途的BeanDefinition

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
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {

//=====================定义众多常量。这一些常量会直接影响到spring实例化Bean时的策略
// 个人觉得这些常量的定义不是必须的,在代码里判断即可。Spring定义这些常量的原因很简单,便于维护,让读代码的人知道每个值的意义(所以以后我们在书写代码时,也可以这么来搞)

//默认的SCOPE,默认是单例
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;

//检查依赖是否合法,在本类中,默认不进行依赖检查
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对象或是类的全限定名
@Nullable
private volatile Object beanClass;

//默认的scope是单例
@Nullable
private String scope = SCOPE_DEFAULT;
//默认不为抽象类
private boolean abstractFlag = false;
//默认不进行自动装配
private boolean lazyInit = false;
//默认不是懒加载
private int autowireMode = AUTOWIRE_NO;
//默认不进行依赖检查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
// @@DependsOn 默认没有
@Nullable
private String[] dependsOn;
// autowire-candidate属性设置为false,这样容器在查找自动装配对象时,将不考虑该bean,
// 备注:并不影响本身注入其它的Bean
private boolean autowireCandidate = true;
// 默认不是首选的
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<String, AutowireCandidateQualifier> 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;

//=====================方法:就不逐一解释了,大部分都是get、set 只贴出一些特殊的

// 其实就是给reource赋值了,使用了BeanDefinitionResource
public void setOriginatingBeanDefinition(BeanDefinition originatingBd) {
this.resource = new BeanDefinitionResource(originatingBd);
}
// 上面有赋值,所以get的时候就是返回上面set进来的值
public BeanDefinition getOriginatingBeanDefinition() {
return (this.resource instanceof BeanDefinitionResource ?
((BeanDefinitionResource) this.resource).getBeanDefinition() : null);
}

//克隆Bean的定义信息
@Override
public Object clone() {
return cloneBeanDefinition();
}
public abstract AbstractBeanDefinition cloneBeanDefinition();
}

AbstractBeanDefinition定义了一系列描述Bean画像的属性,通过这个类,可以窥见Bean的某些默认设置(例如默认为单例等)。

从上图可以看出,接下俩需要看具体衍生出来的实现类了,先看RootBeanDefinitionChildBeanDefinitionGenericBeanDefinition。他们都是AbstractBeanDefinition的直接实现类

GenericBeanDefinition

标准bean definition,通用的

除了具有指定类、可选的构造参数值和属性参数这些其它bean definition一样的特性外,它还具有通过parenetName属性来灵活(动态)设置parent bean definition,而非硬编码作为root bean definition

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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")); //Generic bean with parent 'com.fsx.bean.Parent': class [com.fsx.bean.Child]; scope=;...
}

GenericBeanDefinition源码实现非常的的简单,只增加了一个parentName的属性值,其余的实现都在父类AbstractBeanDefinition

备注:若你是xml配置,最初被加载进来都是一个GenericBeanDefinition,之后再逐渐解析的。

ChildBeanDefinition

子Bean定义信息,依赖于父类RootBeanDefinition

ChildBeanDefinition是一种bean definition,它可以继承它父类的设置,即ChildBeanDefinitionRootBeanDefinition有一定的依赖关系

从spring 2.5 开始,提供了一个更好的注册bean definition类GenericBeanDefinition,所以以后推荐使用它。

RootBeanDefinition

一个RootBeanDefinition定义表明它是一个可合并的bean definition:即在spring beanFactory运行期间,可以返回一个特定的bean。但在Spring2.5以后,我们绝大多数情况还是可以使用GenericBeanDefinition来做。

​ 我们非常熟悉的final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);这句代码,就是去合并parent的属性进来,这样体现了继承的强大。属性也才完整。

​ 在 配置文件中可以定义父和子,父用RootBeanDefinition表示, 而子用ChildBeanDefiniton表示,而没有父的就使用 RootBeanDefinition表示。下面看看源码:

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
//简单的说:在多继承体系中,RootBeanDefinition代表的是当前初始化类的父类的BeanDefinition 若没有父类,那就是它自己嘛
public class RootBeanDefinition extends AbstractBeanDefinition {

//BeanDefinitionHolder存储有Bean的名称、别名、BeanDefinition
@Nullable
private BeanDefinitionHolder decoratedDefinition;
// AnnotatedElement 是java反射包的接口,通过它可以查看Bean的注解信息
@Nullable
private AnnotatedElement qualifiedElement;
//允许缓存
boolean allowCaching = true;
//从字面上理解:工厂方法是否唯一
boolean isFactoryMethodUnique = false;
//封装了java.lang.reflect.Type,提供了泛型相关的操作,具体请查看:
// ResolvableType 可以专题去了解一下子,虽然比较简单 但常见
@Nullable
volatile ResolvableType targetType;
//缓存class,表明RootBeanDefinition存储哪个类的信息
@Nullable
volatile Class<?> resolvedTargetType;
//缓存工厂方法的返回类型
@Nullable
volatile ResolvableType factoryMethodReturnType;

/** Common lock for the four constructor fields below */
final Object constructorArgumentLock = new Object();

//缓存已经解析的构造函数或是工厂方法,Executable是Method、Constructor类型的父类
@Nullable
Executable resolvedConstructorOrFactoryMethod;
//表明构造函数参数是否解析完毕
boolean constructorArgumentsResolved = false;
//缓存完全解析的构造函数参数
@Nullable
Object[] resolvedConstructorArguments;
//缓存待解析的构造函数参数,即还没有找到对应的实例,可以理解为还没有注入依赖的形参
@Nullable
Object[] preparedConstructorArguments;

/** Common lock for the two post-processing fields below */
final Object postProcessingLock = new Object();

//表明是否被MergedBeanDefinitionPostProcessor处理过
boolean postProcessed = false;
//在生成代理的时候会使用,表明是否已经生成代理
@Nullable
volatile Boolean beforeInstantiationResolved;

//实际缓存的类型是Constructor、Field、Method类型
@Nullable
private Set<Member> externallyManagedConfigMembers;
//InitializingBean中的init回调函数名——afterPropertiesSet会在这里记录,以便进行生命周期回调
@Nullable
private Set<String> externallyManagedInitMethods;
//DisposableBean的destroy回调函数名——destroy会在这里记录,以便进行生命周期回调
@Nullable
private Set<String> externallyManagedDestroyMethods;

//===========方法(只例举部分)
// 由此看出,RootBeanDefiniiton是木有父的
@Override
public String getParentName() {
return null;
}
@Override
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}

// 拿到class类型
@Nullable
public Class<?> getTargetType() {
if (this.resolvedTargetType != null) {
return this.resolvedTargetType;
}
ResolvableType targetType = this.targetType;
return (targetType != null ? targetType.resolve() : null);
}

@Override
public RootBeanDefinition cloneBeanDefinition() {
return new RootBeanDefinition(this);
}
}

可以看到许多与反射相关的对象,这说明spring底层采用的是反射机制

总结一下,RootBeanDefiniiton保存了以下信息:

  1. 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)

  2. Bean的注解(AnnotatedElement)

  3. 具体的工厂方法(Class类型),包括工厂方法的返回类型,工厂方法的Method对象

  4. 构造函数、构造函数形参类型

  5. Bean的class对象

可以看到,RootBeanDefinition与AbstractBeanDefinition是互补关系,RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本完善

AnnotatedBeanDefinition的相关子类

ScannedGenericBeanDefinition

存储@Component、@Service、@Controller等注解注释的类

它的源码很简单,就是多了一个属性:private final AnnotationMetadata metadata用来存储扫描进来的Bean的一些注解信息。

1
2
3
4
5
6
7
8
9
10
11
// 实现了AnnotatedBeanDefinition 也继承了GenericBeanDefinition
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
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应用着,它使用得非常的多。因为获取注解信息非常的方便~

只能用于已经被注册或被扫描到的类(否则你手动new一个,它就不在容器里了,那就脱离管理了)

使用案例
1
2
3
4
5
6
7
8
public static void main(String[] args) {
AnnotatedBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(RootConfig.class);
// 就这么一下子,就把注解们都拿到了,简直不要太方便,简直可以当工具类来用
Set<String> annotationTypes = beanDefinition.getMetadata().getAnnotationTypes();
System.out.println(annotationTypes); //[org.springframework.context.annotation.ComponentScan, org.springframework.context.annotation.Configuration]
System.out.println(beanDefinition.isSingleton()); //true
System.out.println(beanDefinition.getBeanClassName()); //com.config.RootConfig
}
源码参考
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
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {

private final AnnotationMetadata metadata;
@Nullable
private MethodMetadata factoryMethodMetadata;

/**
* Create a new AnnotatedGenericBeanDefinition for the given bean class.
* @param beanClass the loaded bean class 注意官方这个注释:已经加载进来了的Bean的Class
*/
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = new StandardAnnotationMetadata(beanClass, true);
}

//@since 3.1.1 此处传入AnnotationMetadata ,也得保证对应的class已经被loaded
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;
}

//@since 4.1.1 可以由指定的工厂方法产生这个Bean
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) {
this(metadata);
Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null");
setFactoryMethodName(factoryMethodMetadata.getMethodName());
this.factoryMethodMetadata = factoryMethodMetadata;
}

@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
@Nullable
public final MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}

}
ConfigurationClassBeanDefinition

首先需要注意的是,它是ConfigurationClassBeanDefinitionReader的一个私有的静态内部类:这个类负责将@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition类(非常的重要)

1
2
3
4
// 它直接继承自RootBeanDefinition 
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {
... 源码和之前的差得不是太多,此处就不解释了
}
默认的设置
  • 如果@Bean注解没有指定bean的名字,默认会用方法的名字命名bean
  • @Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会成为工厂方法,通过工厂方法实例化Bean,而不是直接通过构造函数初始化(所以我们方法体里面可以很方便的书写逻辑。。。)

BeanDefinition的使用

Spring初始化时,会用GenericBeanDefinition或是ConfigurationClassBeanDefinition用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition

BeanDefinitionBuilder

快速创建一个Bean定义

使用它的好处是,可以进行方法的连缀。
没有特殊指明,创建的都是GenericBeanDefinition,源码非常的简单,下面只用个Deme看看即可

1
2
3
4
5
6
7
8
9
10
11
12
13
public class BeanDefinitionBuilder {
//=================创建一个Builder 没特殊指明,都是GenericBeanDefinition
public static BeanDefinitionBuilder genericBeanDefinition() {
return new BeanDefinitionBuilder(new GenericBeanDefinition());
}
....
public static BeanDefinitionBuilder rootBeanDefinition(String beanClassName) {
return rootBeanDefinition(beanClassName, null);
}
public static BeanDefinitionBuilder childBeanDefinition(String parentName) {
return new BeanDefinitionBuilder(new ChildBeanDefinition(parentName));
}
}
示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Child.class)
.setRole(BeanDefinition.ROLE_APPLICATION)
.setScope(BeanDefinition.SCOPE_SINGLETON)
.addPropertyValue("name", "fsx")
.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

该接口的作用就是加载 Bean

​ 在 Spring 中,Bean 一般来说都在配置文件中定义。而在配置的路径由在 web.xml 中定义(还有全注解的方 式)。所以加载 Bean 的步骤大致就是:

  1. 加载资源,通过配置文件的路径(Location)加载配置文件(Resource)
  2. 解析资源,通过解析配置文件的内容得到 Bean。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface BeanDefinitionReader {

// 得到Bean定义的register
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;

}

它的继承结构非常简单,一个抽象实现+3个具体实现

AbstractBeanDefinitionReader

它实现了一些基本的方法,但是核心方法loadBeanDefinitions肯定是交给子类实现了

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
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();

// 此构造函数,会完成一些参数的初始化
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();
}
}

public void setEnvironment(Environment environment) {
Assert.notNull(environment, "Environment must not be null");
this.environment = environment;
}
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new DefaultBeanNameGenerator());
}

...
}

评论