BeanDefinition
从我的上一篇文章你可以知道,BeanDefinition
定义了一个Bean大概需要什么信息,给这些信息定义了一些getter和setter方法,作为接口层它不负责定义具体的参数,AbstractBeanDefinition
对这个接口进行了实现,它提供了一个BeanDefinition
所需要具备的基本能力,如果需要扩展功能,那么可以对这个类进行继承,再添砖加瓦即可。今天我们来看看AbstractBeanDefinition
的三个子类:
- RootBeanDefinition
- ChildBeanDefinition
- GenericBeanDefinition
RootBeanDefinition
从Spring2.5开始,RootBeanDefinition仅作为运行时的BeanDefinition视图。如果需要编程定义BeanDefinition,那么推荐使用GenericBeanDefinition。
Spring的解释是:GenericBeanDefinition的优势在于,它允许动态定义父依赖项,而不是一个以"硬编码"定义BeanDefinition的角色。
也就是说,bean的一般形式是以GenericBeanDefinition的标准形式存在的,在特定的时机,会将GenericBeanDefinition转成RootBeanDefinition
RootBeanDefinition特点
- 存储
BeanDefinitionHolder
对象,该对象用来存储Bean的name与alias的对应关系,提供BeanDefinition
的访问方式 -
AnnotatedElement
,这个是Java反射包的注解,开发者可以通过它来操作注解。如平时常见到的getAnnotation()
、getAnnotations()
、isAnnotationPresent()
等 -
allowCaching
,是否允许缓存 -
isFactoryMethodUnique
,工厂方法是否唯一 -
targetType
,与Java泛型相关的工具类 -
resolvedTargetType
,当前类持有的Class对象 -
factoryMethodToIntrospect
,缓存工厂方法 -
Executable
,缓存已经解析的构造函数或者方法,Executable是Method和Construct的父类 -
constructorArgumentsResolved
,布尔值,表示构造函数是否被解析完毕 -
resolvedConstructorArguments
,缓存被完全解析的构造函数参数 -
postProcessed
,是否被MergedBeanDefinitionPostProcessor处理 -
beforeInstantiationResolved
,已启动实例化前的后处理器 -
externallyManagedInitMethods
,初始化时的回调函数 -
externallyManagedDestroyMethods
,销毁时的回调函数 -
constructorArgumentLock
和postProcessingLock
,对象锁,有兴趣的可以自行深入。这里不做阐述
此外,RootBeanDefinition不可以进行setParentName()操作。
可以看到它存储了许多关于注解与反射相关的信息,这或许会在某些时机用到这些信息进行反射。
Demo
通过Java代码来实例化一个RootBeanDefinition
Root
public class Root {
private String name;
private String description;
private boolean isRoot;
public Root() {
}
/**
* 构造函数
* @param name 名称 对应的index为 0
* @param description 描述 对应的index为 1
* @param isRoot 是否是父BeanDefinition 对应的index为 2
*/
public Root(String name, String description, Boolean isRoot) {
this.name = name;
this.description = description;
this.isRoot = isRoot;
}
@Override
public String toString() {
return "Root{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
", isRoot=" + isRoot +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean getIsRoot() {
return isRoot;
}
public void setIsRoot(boolean root) {
isRoot = root;
}
}
Child
package com.xjm.model;
/**
* @author jaymin
* 2020/11/29 14:21
*/
public class Child {
private String name;
private String description;
private boolean isRoot;
private String parentName;
public Child(String name, String description, boolean isRoot, String parentName) {
this.name = name;
this.description = description;
this.isRoot = isRoot;
this.parentName = parentName;
}
public Child() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public boolean getIsRoot() {
return isRoot;
}
public void setIsRoot(boolean root) {
isRoot = root;
}
public String getParentName() {
return parentName;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
@Override
public String toString() {
return "Child{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
", isRoot=" + isRoot +
", parentName='" + parentName + '\'' +
'}';
}
}
这里定义的对象待会会复用,我就不重新定义了
RootBeanDefinitionDemo
package com.xjm.bean.definition;
import com.xjm.model.Root;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author jaymin<br>
* <p>
* 2020/11/29 13:28
*/
@SuppressWarnings("all")
public class RootBeanDefinitionDemo {
/**
* 通过构造器注入参数获取RootBeanDefinition
*
* @return
*/
public static RootBeanDefinition getRootBeanDefinitionByConstruct() {
ConstructorArgumentValues cargs = new ConstructorArgumentValues();
cargs.addIndexedArgumentValue(0, "rootA");
cargs.addIndexedArgumentValue(1, "This is a RootBeanDefinition");
cargs.addIndexedArgumentValue(2, true);
RootBeanDefinition rootBeanDefinitionA = new RootBeanDefinition(Root.class, cargs, null);
return rootBeanDefinitionA;
}
/**
* 通过Setter的方式注入参数,返回RootBeanDefinition
*
* @return
*/
public static RootBeanDefinition getRootBeanDefinitionBySetter() {
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("name", "rootB");
propertyValues.addPropertyValue("description", "This is a RootBeanDefinition");
propertyValues.addPropertyValue("isRoot", true);
RootBeanDefinition rootBeanDefinitionB = new RootBeanDefinition(Root.class, null, propertyValues);
return rootBeanDefinitionB;
}
public static void main(String[] args) {
// 1. 构建一个空的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 2.创建一个RootBeanDefinition
RootBeanDefinition rootBeanDefinitionA = getRootBeanDefinitionByConstruct();
RootBeanDefinition rootBeanDefinitionB = getRootBeanDefinitionBySetter();
applicationContext.registerBeanDefinition("rootA", rootBeanDefinitionA);
applicationContext.registerBeanDefinition("rootB", rootBeanDefinitionB);
// 这里埋一个点,直到这里才调用了Root对象的构造函数
applicationContext.refresh();
Root rootA = ((Root) applicationContext.getBean("rootA"));
Root rootB = ((Root) applicationContext.getBean("rootB"));
System.out.println(rootA.toString());
System.out.println(rootB.toString());
}
}
ChildBeanDefinition
支持setParentName(),参数为父RootBeanDefinition的name,通过构造函数的方式进行设置继承关系.Spring的注释写到多数情况下GenericBeanDefinition可以替代ChildBeanDefinition,所以这里就不详细讲了,提供一个demo供大家品味.
ChildBeanDefinitionDemo
package com.xjm.bean.definition;
import com.xjm.model.Child;
import com.xjm.model.Root;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author jaymin<br>
* <p>
* 2020/11/29 14:20
*/
@SuppressWarnings("all")
public class ChildBeanDefinitionDemo {
public static void main(String[] args) {
// 1. 构建一个空的容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
String parentName = "rootB";
String childName = "child";
RootBeanDefinition rootBeanDefinition = RootBeanDefinitionDemo.getRootBeanDefinitionBySetter();
ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition(parentName);
childBeanDefinition.setBeanClass(Child.class);
childBeanDefinition.getPropertyValues().addPropertyValue("parentName", parentName);
childBeanDefinition.getPropertyValues().addPropertyValue("isRoot", false);
// 注册
applicationContext.registerBeanDefinition(parentName, rootBeanDefinition);
applicationContext.registerBeanDefinition(childName, childBeanDefinition);
// 刷新上下文
applicationContext.refresh();
Root root = applicationContext.getBean(Root.class);
Child child = (Child) applicationContext.getBean(childName);
System.out.println(root.toString());
System.out.println(child.toString());
}
}
GenericBeanDefinition
提供了setParentName()的方法,并且是setter的方式,通过读Spring的注释,它如此描述道:
GenericBeanDefinition是一站式商店,用于标准bean定义。像任何bean定义一样,它允许指定一个类以及可选的构造函数参数值和属性值。另外,可以通过“ parentName”属性灵活地配置从父bean定义派生的内容。
GenericBeanDefinitionDemo
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;
/**
* @author jaymin
* 2020/11/29 14:57
*/
public class GenericBeanDefinitionDemo {
public 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;
}
public 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());
}
}
可以看到,我们只用了一个GenericBeanDefinition就可以完成RootBeanDefinition和RootBeanDefinition能做到的事情。只需要setParentName(),就可以拷贝另一个BeanDefinition的信息。易于扩展
留给读者的话
Spring源码工程非常地庞大,但是提供了大量的注释,有的时候光变量就一大堆,我们怎么让这些东西给我们留下一个深刻的印象呢,唯有实践加上思考。我个人知识储量尚未足够丰富,只能留下一些代码,有兴趣的朋友可以自行跟着实现一下,感受一下Spring的强大之处。至于更深层的原理,目前尚未能完全讲的透彻。如有不对的地方,欢迎指正。