highlight: arduino-light
theme: juejin
BeanDefinition的实现类。包括AbstractBeanDefinition、RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition、AnnotateGenericBeanDefinition、ScannerGenericBeanDefinition。
1.AbstractBeanDefinition
AbstractBeanDefinition是抽象类,它是众多BeanDefinition子类的父类。
前两篇文章讲的BeanDefinition属性值大都保存在AbstractBeanDefinition,并实现了子BeanDefinition通用方法。同时它也继承了BeanMetadataAttributeAccessor完成attribute和source的操作。
我们看一下它的关键源码,重点属性使用★标记出来了:
```java //AbstractBeanDefinition extends BeanMetadataAttributeAccessor ★ //AbstractBeanDefinition继承了BeanMetadataAttributeAccessor //BeanMetadataAttributeAccessor是BeanDefinition的实现类 //那么借用上一批文章中的总结:BeanDefinition的实现类BeanMetadataAttributeAccessor实现 //BeanMetadataElement继承了AttributeAccessorSupport。既可以设置和获取源,也可以设置和获取bd的属性值。 //所以AbstractBeanDefinition既可以设置和获取源,也可以设置和获取bd的属性值。 public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {
// 此处省略静态变量以及final变量
/**
* bean的对应的class ★
*/
@Nullable
private volatile Object beanClass;
/**
* bean的作用范围,对应bean属性scope即单例、多例 ★
*/
@Nullable
private String scope = SCOPE_DEFAULT;
/**
* 是否是抽象,对应bean属性abstract ★
*/
private boolean abstractFlag = false;
/**
* 是否延迟加载,对应bean属性lazy-init ★
*/
private boolean lazyInit = false;
/**
* 自动注入模式,对应bean属性autowire ★
*/
private int autowireMode = AUTOWIRE_NO;
/**
* 依赖检查,Spring 3.0后弃用这个属性
*/
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
/**
* 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-on★
*/
@Nullable
private String[] dependsOn;
/**
* autowireCandidate ★
* autowireCandidate属性设置为false时容器在查找自动装配对象时,
* 将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,
* 但是该bean本身还是可以使用自动装配来注入其他bean
*/
private boolean autowireCandidate = true;
/**
* 自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primary ★
*/
private boolean primary = false;
/**
* 用于记录Qualifier,对应子元素qualifier ★
*/
private final Map<String, AutowireCandidateQualifier> qualifiers= new LinkedHashMap<>(0);
@Nullable
private Supplier<?> instanceSupplier;
/**
* 允许访问非公开的构造器和方法,程序设置
*/
private boolean nonPublicAccessAllowed = true;
/**
* 是否以一种宽松的模式解析构造函数,默认为true,
* 如果为false,则在以下情况
* interface ITest{}
* class ITestImpl implements ITest{};
* class Main {
* Main(ITest i) {}
* Main(ITestImpl i) {}
* }
* 抛出异常,因为Spring无法准确定位哪个构造函数程序设置
*/
private boolean lenientConstructorResolution = true;
/**
* factoryBeanName ★
* 对应bean属性factory-bean,用法:
* <bean id = "instanceFactoryBean" class = "example.chapter3.InstanceFactoryBean" />
* <bean id = "currentTime" factory-bean = "instanceFactoryBean" factory-method = "createTime" />
*意思是通过InstanceFactoryBean的方法createTime创建currentTime
*/
@Nullable
private String factoryBeanName;
/**
* 对应bean属性factory-method ★
*/
@Nullable
private String factoryMethodName;
/**
* 记录构造函数注入属性,对应bean属性constructor-arg
*/
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
/**
* 普通属性集合,就是存放你业务类的属性的地方★
*/
@Nullable
private MutablePropertyValues propertyValues;
/**
* 方法重写的持有者,记录lookup-method、replaced-method元素★
* 目前很少用了
*/
@Nullable
private MethodOverrides methodOverrides;
/**
* 初始化方法,对应bean属性init-method ★
*/
@Nullable
private String initMethodName;
/**
* 销毁方法,对应bean属性destroy-method ★
*/
@Nullable
private String destroyMethodName;
/**
* 是否执行init-method,程序设置
*/
private boolean enforceInitMethod = true;
/**
* 是否执行destroy-method,程序设置
*/
private boolean enforceDestroyMethod = true;
/**
* 是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true,程序设置
* synthetic意思是合成的
*/
private boolean synthetic = false;
/**
* 定义这个bean的应用范围 ★
* APPLICATION:用户
* INFRASTRUCTURE:完全内部使用,与用户无关
* SUPPORT:某些复杂配置的一部分,程序设置
*/
private int role = BeanDefinition.ROLE_APPLICATION;
/**
* bean的描述信息
*/
@Nullable
private String description;
/**
* 这个bean定义的资源
*/
@Nullable
private Resource resource;
}
```
操作方法我就不列出来了,主要就是对属性的设置和获取,类似于getter和setter方法,读者自行阅读。
这些属性很重要,建议多读几遍加深印象!
这些属性很重要,建议多读几遍加深印象!
这些属性很重要,建议多读几遍加深印象!
总之,AbstractBeanDefinition 就是保存了属性值并对属性值进行设置和读取。记住这一点就行了。
AbstractBeanDefinition 其实已经涵盖了所有属性了,spring为什么要提供这么多的子类?
正所谓,既生瑜何生亮!
笔者认为,完全可以用一个AbstractBeanDefinition 代替所有的子类,只不过spring为了模块化,不同的BeanDefinition可能从代码角度来讲都一样,但是从设计角度来讲我们要模块化,要拆分。
不同模块的BeanDefinition无论从设计还是功能肯定有差异,我们当然可以将这些差异规避在AbstractBeanDefinition ,但是这不利于维护和扩展,更不利于阅读理解。
打个比方,最近在做通用告警模板,告警的方式有3种钉钉、企微、飞书。
每个告警方式都提供了不同的api供我们调用,每个api的入参的参数类型、参数名称都不相同。
比如钉钉用的是msgType、飞书用的是msg_type、企微用的是messageType
当然,我们可以提供1个WarnPushDTO,把钉钉、企微、飞书的参数都放进去。
java @Data public class WarnPushDTO{ private String msgType; private String msg_type; private String messageType; }
然后提供1个统一的告警方法。
public static void warnPush(WarnPushDTO dto)
看起来完美!但是对于用的人来说可能就很不友好了,我要用企微,该设置哪个参数呢?
对于用的人来说,我只知道我需要调用企微的告警,你不需要给我搞那些有的没的!
针对这个问题怎么解决呢?上代码:
java @Data public class WarnPushDTO{ } @Data public class weChatWarnPushDTO extends WarnPushDTO{ private String messageType; }
在调用warnPush方法的时候传入 new weChatWarnPushDTO().setMessageType("text");
哎,这就是迪米特法则嘛也就是最小知识法则! 我不需要知道的我不用知道!
对于BeanDefinition也是如此,某些BeanDefinition只用于某些固定的场景,只需要操作某些固定的属性即可。所以对于某些我不需要特意去操作的属性,我也没必要知道你的存在。我只操作我要操作的属性即可。相当于把细节和通用的属性都放在了父类中。
为什么AbstractBeanDefinition
没有像上面一样把所有的属性都放在子类中呢?
个人理解是某些BeanDefinition只用于某些固定的场景,只需要操作某些固定的属性即可,但是有一些通用的属性还是需要的,所以把这些通用的属性全都放在了AbstractBeanDefinition
中,如果真的需要操作那么直接调用super的方法即可。
AbstractBeanDefinition的MutablePropertyValues
这里讲一下这行代码。这行代码设置的是对象的属性值。
java //设置beanDefinition的属性值 beanDefinition.setAttribute("name","源码之路"); //设置对象的属性值 beanDefinition.getPropertyValues().addPropertyValue("name","彭方亮");
上文AbstractBeanDefinition 源码中有一个MutablePropertyValues类型的属性叫propertyValues
java /** * 普通属性集合,就是存放你业务类的属性的地方 */ @Nullable private MutablePropertyValues propertyValues;
什么意思呢?propertyValues只能保存你业务类的属性,比如业务类InterService中有个name属性.
java root.getPropertyValues().add("name","源码之路");
在后期spring实例化过程中,会将propertyValues中的属性值一一对应的赋值给业务对象。
等同于xml文件中的配置:
java <bean id="index" class="com.InterService" > <property name="name" value="源码之路"></property> </bean>
如果,我设置了一个在InterService类中不存在的属性,就会报错,比如设置1个age属性。
我说过,AbstractBeanDefinition中的属性以后都会讲到,别急,这个propertyValues知道啥意思了吧?
propertyValues区别于attribute:
attributribute是beanDefinition的属性比如懒加载、单例等。
propertyValues是对象的属性比如年龄、身高等。
java //设置属性值 beanDefinition.setAttribute("AttributeAccessor","源码之路"); //将beanDefinition注册到spring容器中 context.registerBeanDefinition("interService",beanDefinition); //加载或者刷新当前的配置信息 context.refresh(); //拿到属性信息 String[] attributes = context.getBeanDefinition("interService").attributeNames();
2.ChildBeanDefinition:必须设置parentName
我们看一下ChildBeanDefinition源码中的类注解:
* <p><b>NOTE:</b> Since Spring 2.5, the preferred way to register bean
* definitions programmatically is the {@link GenericBeanDefinition} class,
* which allows to dynamically define parent dependencies through the
* {@link GenericBeanDefinition#setParentName} method. This effectively
* supersedes the ChildBeanDefinition class for most use cases.
翻译一下
spring2.5以后GenericBeanDefinition是首选的,也就是说spring2.5以前的版本根本就没有GenericBeanDefinition这个类。
Spring总得向前发展啊,更重要的是尽可能的保持向下兼容呀!
其实,RootBeanDefinition也有这种类似的注解,你不信你去看源码!
现如今,我们已经不使用ChildBeanDefinition了,完全被GenericBeanDefinition给替代了,但是还在使用RootBeanDefinition。
ChildBeanDefinition不能独立存在,他必须继承一个父类,为什么?我们看源码:
```java public class ChildBeanDefinition extends AbstractBeanDefinition {
//父类名称
@Nullable
private String parentName;
/**
* 构造函数,必须设置一个父类
*/
public ChildBeanDefinition(String parentName) {
super();
this.parentName = parentName;
}
/**
* 构造函数,设置父类和业务类属性
*/
public ChildBeanDefinition(String parentName, MutablePropertyValues pvs) {
super(null, pvs);
this.parentName = parentName;
}
/**
* 构造函数,设置父类,业务类构造函数的参数,业务类属性
*/
public ChildBeanDefinition(String parentName,
ConstructorArgumentValues cargs,
MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
}
/**
* 构造函数,设置父类,业务类beanClass,业务类构造函数的参数,业务类属性
*/
public ChildBeanDefinition( String parentName,
Class<?> beanClass,
ConstructorArgumentValues cargs,
MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
setBeanClass(beanClass);
}
/**
* 构造函数,设置父类,业务类名称,业务类构造函数的参数,业务类属性
*/
public ChildBeanDefinition(String parentName,
String beanClassName,
ConstructorArgumentValues cargs,
MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
setBeanClassName(beanClassName);
}
/**
* 构造函数,从另一个ChildBeanDefinition进行属性copy
*/
public ChildBeanDefinition(ChildBeanDefinition original) {
super(original);
}
//设置父类名称
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
//获取父类名称
@Override
@Nullable
public String getParentName() {
return this.parentName;
}
//校验,会发现,如果没有父类就会报错
@Override
public void validate() throws BeanDefinitionValidationException {
super.validate();
if (this.parentName == null) {
throw new BeanDefinitionValidationException
("'parentName' must be set in ChildBeanDefinition");
}
}
//生成一个新的ChildBeanDefinition,并进行属性值复制
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
return new ChildBeanDefinition(this);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ChildBeanDefinition)) {
return false;
}
ChildBeanDefinition that = (ChildBeanDefinition) other;
return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName)
&& super.equals(other));
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.parentName) * 29 + super.hashCode();
}
@Override
public String toString() {
return "Child bean with parent '" + this.parentName + "': " + super.toString();
}
}
```
ChildBeanDefinition所有的构造方法都要求设置父类名称,所以从代码角度讲,它必须依赖于父类存在,不能单独存在。
spring官方当初设置ChildBeanDefinition的初衷就是永远让它作为一个子bd存在。但是它现在完全可以被GenericBeanDefinition替代了。
继续,再添加一个业务类:
```java public class User { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } }
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
//模板BeanDefinition
RootBeanDefinition root = new RootBeanDefinition();
//设置为抽象类
root.setAbstract(true);
root.setDescription("我是一个模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源码之路");
//注册,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child继承root
ChildBeanDefinition child = new ChildBeanDefinition("interService");
child.setBeanClass(User.class);
//注册,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((User)context.getBean("child")).getName());
}
}
```
也就是说User类相当于继承了InterService类,等同于xml文件:
xml <bean id="interService" class="com.InterService" > <property name="name" value="源码之路"></property> </bean> <bean id="user" class="com.User" parent="interService"> </bean>
这里很绕,笔者当时为了弄懂这里也是费了好大的劲,多读两遍就理解了!
3.RootBeanDefinition:不能设置parentName
一般Spring自己的类会被注册为RootBeanDefinition。
Root,Child根据字面意思,好像是父子关系,AbstractBeanDefinition 中有个属性叫abstract(是否是抽象类),抽象类无法实例化呀,不能保存到beanDefinitionMap容器中啊!有存在的意义吗?
有,模板!
如果一个BeanDefinition中的属性abstract为true,它是让spring来继承它,而不是实例化它。
举个例子吧:
```java //业务类 public class InterService { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //注册配置类 context.register(Config.class);
//设置父类BeanDefinition 即模板BeanDefinition
RootBeanDefinition root = new RootBeanDefinition();
//设置为抽象类
//这里不一定要设置为true 使用false也是没问题的
root.setAbstract(true);
root.setDescription("我是一个模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源码之路");
//注册,放到IOC容器中
context.registerBeanDefinition("interService",root);
//设置子类BeanDefinition继承RootBeanDefinition
//interService即Parentname 即父BeanDefinitionName
//这是ChildBeanDefinition的构造参数
ChildBeanDefinition child = new ChildBeanDefinition("interService");
//注册,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
//获取child的name属性 继承自RootBeanDefinition
System.out.println
(((InterService)context.getBean("child")).getName());
}
} ```
打印结果:
RootBeanDefinition不可以替换ChildBeanDefinition
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
//模板BeanDefinition
RootBeanDefinition root = new RootBeanDefinition();
//设置为抽象类
root.setAbstract(true);
root.setDescription("我是一个模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源码之路");
root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
//注册,放到IOC容器中
context.registerBeanDefinition("interService",root);
//使用 RootBeanDefinition代替 childBeanDefinitio
RootBeanDefinition child = new RootBeanDefinition();
child.setParentName("interService");
child.setBeanClass(User.class);
//注册,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((User)context.getBean("child")).getName());
System.out.println(context.getBeanDefinition("child").getScope());
}
}
为什么会报错?
我们看child.setParentName("interService")这行代码的源码。
即RootBeanDefinition的setParentName源码:
@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");
}
}
看到了吧,你设置父类的时候spring给你抛异常,不允许。RootBeanDefinition的所有构造函数也不给你提供一个设置父类的参数。
那么问题来了,spring为什么这么做?
笔者构建好了spring源码,然后笔者把RootBeanDefinition的源码改了: 首先,在RootBeanDefinition增加一个parentName的属性
java @SuppressWarnings("serial") public class RootBeanDefinition extends AbstractBeanDefinition { ..... //父类名称 private String parentName; .... }
其次,修改setParentName
java @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"); //} this.parentName = parentName; }
最后修改getParentName方法,注意,spring原来的就是return null;
@Override
public String getParentName() {
//return null;
return this.parentName;
}
打印结果:
此时,RootBeanDefinition充当了ChildBeanDefinition的角色。
spring为什么这么做?
不要告诉我setParentName抛异常所以不允许,我已经证明该源码可以了。
我问的是spring源码作者他当时咋想的?
我给你打个样:这里涉及到bean合并。
(18条消息) spring之Bean的生命周期之BeanDefinition的合并解析_kznsbs的博客-CSDN博客
最后读下RootBeanDefinition的源码吧:
```java public class RootBeanDefinition extends AbstractBeanDefinition {
//BeanDefinitionHolder存储有Bean的名称、别名数组、BeanDefinition
//是对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需要的信息基本完善
4.GenericBeanDefinition:parentName非必需
上文我们说GenericBeanDefinition可以替代RootBeanDefinition和ChildBeanDefinition,原因是GenericBeanDefinition的parentName属性是可以设置也可以不设置,我们测试一下:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
//模板BeanDefinition
GenericBeanDefinition root = new GenericBeanDefinition();
//设置为抽象类
root.setAbstract(true);
root.setDescription("我是一个模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源码之路");
root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
//注册,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child继承root
GenericBeanDefinition child = new GenericBeanDefinition();
child.setParentName("interService");
child.setAbstract(false);
child.setBeanClass(User.class);
//注册,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((User)context.getBean("child")).getName());
System.out.println(context.getBeanDefinition("child").getScope());
}
}
打印结果:
我们阅读下GenericBeanDefinition源码:
```java public class GenericBeanDefinition extends AbstractBeanDefinition {
//父BeanDefinition名字
@Nullable
private String parentName;
/**
* 构造方法,所有属性均为空
*/
public GenericBeanDefinition() {
super();
}
/**
* 从一个给定的BeanDefinition中将属性值copy给新的GenericBeanDefinition
*/
public GenericBeanDefinition(BeanDefinition original) {
super(original);
}
//设置父类名称
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
//获取父类名称
@Override
@Nullable
public String getParentName() {
return this.parentName;
}
//根据当前GenericBeanDefinition克隆一个新的GenericBeanDefinition
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
return new GenericBeanDefinition(this);
}
@Override
public boolean equals(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() {
StringBuilder sb = new StringBuilder("Generic bean");
if (this.parentName != null) {
sb.append(" with parent '").append(this.parentName).append("'");
}
sb.append(": ").append(super.toString());
return sb.toString();
}
}
```
我们来做个总结吧:
RootBeanDefinition作为父bd出现,不能作为子bd出现。
ChildBeanDefinition必须作为子bd出现。
GenericBeanDefinition可以作为父bd出现,也可以作为子bd出现。它可以完全替代ChildBeanDefinition,但不能完全替代RootBeanDefinition,这一点在以后的bean合并博文中会讲解,敬请期待。
现如今,大家都用spring注解扫描的方式进行开发,首先在业务类上添加一个注解,比如@Service、@Controller、@Component等,spring扫描所有类并判断是否加入相关注解,有注解的类会生成一个BeanDefinition并添加到IOC容器中。我们称它为注解BeanDefinition即AnnotatedBeanDefinition。 AnnotatedBeanDefinition是一个注解bd的接口,可以获取BeanDefinition注解相关数据。
它有3个实现类:
ScannedGenericBeanDefinition
AnnotatedGenericBeanDefinition
ConfigurationClassBeanDefinition
5.ScannedGenericBeanDefinition:扫描注解生成的BD
被@Component注解的类,会生成ScannedGenericBeanDefinition类型的BeanDefinition。
其它继承了@Component的注解如@Service、@Controller、@Repository @Configuration
注意@Configuration注解上有@Component注解
也会生成ScannedGenericBeanDefinition类型的Bean定义。
java ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition
ScannedGenericBeanDefinition实现了AnnotatedBeanDefinition接口且继承了GenericBeanDefinition类,scan翻译成中文就是扫描的意思,顾名思义,它就是spring的Scaner扫描后生成的BeanDefinition。
```java //业务类 @Component @Description("业务类") @Scope("singleton") public class InterService {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
//测试类 public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //注册配置类 context.register(Config.class); context.refresh(); ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) context.getBeanDefinition("interService"); //查看spring给我生成的具体BeanDefinition类型 System.out.println(beanDefinition.getClass().getSimpleName()); //获取注解信息 AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); //获取工厂方法元数据 MethodMetadata methodMetadata = beanDefinition.getFactoryMethodMetadata(); System.out.println(); } } ```
测试结果:
6.AnnotatedGenericBeanDefinition
AnnotatedBeanDefinitionReader注册的BD
通过AnnotatedBeanDefinitionReader的register方法注册上去的BeanDefinition
AnnotatedBeanDefinition接口源码很容易理解:
java public interface AnnotatedBeanDefinition extends BeanDefinition { /** * 获取bean上的所有的注解信息 如@Component */ AnnotationMetadata getMetadata(); /** * 获取此bean的工厂方法的元数据(如果有)。 */ @Nullable MethodMetadata getFactoryMethodMetadata(); }
这两个方法是在子类中实现的,我们先查看这两个方法返回的具体信息:
AnnotationMetadata你就理解为存储了业务类的注解信息,便于spring后续的解析
spring启动时会生成一个AnnotatedBeanDefinitionReader读取器:
```java public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //注册配置类 context.register(Config.class); context.refresh(); System.out.println (context.getBeanDefinition ("interService").getClass().getSimpleName());
System.out.println();
}
}
public AnnotationConfigApplicationContext() { //在IOC容器中初始化一个 注解bean读取器AnnotatedBeanDefinitionReader this.reader = new AnnotatedBeanDefinitionReader(this); //在IOC容器中初始化一个 按类路径扫描注解bean的 扫描器 this.scanner = new ClassPathBeanDefinitionScanner(this); } ```
AnnotatedGenericBeanDefinition的加载过程
其实都是通过AnnotatedBeanDefinitionReader的register方法注册上去的。
自定义加载配置类
主要看这行代码: context.register(Config.class);
查看以下源码:
java context.register(Config.class) ->this.reader.register(componentClasses); ->registerBean(componentClass); ->doRegisterBean(beanClass, null, null, null); ->doRegisterBean()
最后跟到doRegisterBean方法:
java //第一行代码 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); .......中间省略........ //最后一行代码,注册到IOC容器 definitionHolder就是封装了BeanDefinition的对象 registry是容器 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
```java public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
// Register bean definition under primary name. String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any. String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } } ```
spring将你的配置定生成了一个AnnotatedGenericBeanDefinition。 我们来测试一下:
java public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //注册配置类 context.register(Config.class); context.refresh(); System.out.println (context.getBeanDefinition("config").getClass().getSimpleName()); System.out.println(); } } //打印结果: //AnnotatedGenericBeanDefinition
自定义加载自定义类
其实就跟上面配置类一样。我们不让spring自动扫描,我们手动注册一个业务类。
```java public class Test { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); //注册配置类 context.register(Config.class); context.refresh();
//手动注册一个业务类
context.register(InterService.class);
System.out.println
(context.getBeanDefinition
("interService").getClass().getSimpleName());
System.out.println();
}
} //打印结果: //AnnotatedGenericBeanDefinition ```
7.ConfigurationClassBeanDefinition
带@Bean方法被处理为ConfigurationClassBeanDefinition
首先需要注意的是,ConfigurationClassBeanDefinition是一个内部类,其外部类是ConfigurationClassBeanDefinitionReader,ConfigurationClassBeanDefinitionReader这个类负责将被@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition类,源码就不过多解释了,和之前几个BeanDefinition差不多。
默认设置
如果@Bean注解没有指定bean的名字,默认会用方法的名字命名bean。
@Configuration注解的类会成为一个代理类,而所有的@Bean注解的方法会成为工厂方法,通过工厂方法实例化Bean,而不是直接通过构造函数初始化。
@Bean注解注释的类会使用构造函数自动装配。
@Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会成为工厂方法。并且这个@Bean注解的方法返回的实例和直接调用@Configuration注解的类的中的@Bean方法是1个!也就是是1个单例!
@Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会被代理,具体代码在
//策略是CglibSubclassingInstantiationStrategy继承自SimpleInstantiationStrategy
//具体看SimpleInstantiationStrategy#instantiate
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
//代理类的增强逻辑
//ConfigurationClassEnhancer.BeanMethodInterceptor#intercept
```java package parse;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import;
@Configuration public class Config { public Config() { System.out.println("------------------------Config实例化了"); }
@Bean
public User getUser(){
return new User();
}
} ```
```java package parse;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
public class ParseTest {
public static void main(String[] args) throws InterruptedException {
start1();
}
public static void start1() {
//其中Config.class可以指定为
//包扫描启动:@ComponentScan("tyrant")
//使用xml文件启动:@ImportResource("applicationContext.xml")
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
context.refresh();
Config config = (Config) context.getBean("config");
Object user = context.getBean("getUser");
System.out.println(config.getUser()== user);
}
}
//结果是true 说明从容器中获取的对象和直接调用config.getUser()获取的对象是同一个对象
```
说明从容器中获取的对象和直接调用config.getUser()获取的对象是同一个对象
```java package tyrant.user; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration
public class User {
@Bean
public User getUser() {
return new User();
}
private int age = 31;
private String name = "user";
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
```
```java package tyrant;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.Ordered;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(BeanAnnotationConfig.class);
context.refresh();
//返回的是getUser方法对应的beanDefinition
BeanDefinition beanDefinition = context.getBeanDefinition("getUser");
//返回的是User对应的beanDefinition
BeanDefinition definition = context.getBeanDefinition("user");
//查看spring给我生成的具体BeanDefinition类型
System.out.println(beanDefinition.getClass().getSimpleName());
System.out.println(definition.getClass().getSimpleName());
}
}
//ConfigurationClassBeanDefinition
//ScannedGenericBeanDefinition
```
@Bean注解生成的BeanDefinition是ConfigurationClassBeanDefinition @Configuration生成的是ScannedGenericBeanDefinition。 @Configuration注解上有@Component注解
至此,BeanDefinition整个家族继承关系讲完了,相信认真读过这三篇博文的读者对BeanDefinition都有深入的理解了,建议读者结合这三篇博文认真练习,BeanDefinition打好基础了后续spring源码的阅读才会游刃有余,否则很难读下去。
笔者相信,BeanDefinition中的很多属性大家都不是很理解在spring中到底起了什么作用,这个没关系,在后续源码学习过程中这些属性的作用会慢慢浮出水面,到时候再回过头复习才会恍然大悟。
总结
通过AnnotatedBeanDefinitionReader注册的类sping都会生成AnnotatedGenericBeanDefinition。
通过注解被Spring自动扫描的都会生成ScannedGenericBeanDefinition。
被@Component注解的类,其它继承了@Component的注解如@Service、@Controller、@Repository @Configuration都会生成ScannedGenericBeanDefinition类型的BeanDefinition。
被@Bean注解的方法会被转换为对应的ConfigurationClassBeanDefinition