BeanDefiniiton详解
spring在构造bean时,不可能像我们主动构造那样,随心所欲的new,赋值、已经完成方法调用。他需要将千差万别的class概括成为一种【统一的描述性】语言,spring提供了一个接口BeanDefintion为我们统一了这种描述bean的元数据。
bean的元数据通常是我们使用xml或者注解进行配置的数据,我们的spring容器启动之间第一步就是加载配置数据,这些元数据会被加载到内存以一个个beanDefinition的形式保存在一个map中。
一个BeanDefiniiton大概保存了以下信息:
1.定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
2.具体的工厂方法(Class类型),包括工厂方法的返回类型,工厂方法的Method对象
3.构造函数、构造函数形参类型
4.Bean的class对象
5.作用范围、是否懒加载等等
以下是BeanDefiniiton的类的结构图,这里没有用类图,我觉得这里用这样的图好看一些:
beanDefinition来源不同可能会有不同实现,目前我们最常用的实现就是GenericBeanDefinition这个实现类。
小知识:Generic(一般的,通用的),几乎所有以这个单词打头的实现,都是spring的通用实现。
1、认识BeanDefinition
BeanDefinition接口定义了大量的常量和方法:
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 常量标志一个bean的作用范围
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// 设置父BeanDefinition,可以只对有父子关系的bean
void setParentName(@Nullable String parentName);
String getParentName();
// bean的类的全限定名
void setBeanClassName(@Nullable String beanClassName);
String getBeanClassName();
void setScope(@Nullable String scope);
String getScope();
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 设置依赖性,被依赖的bean会优先创建
void setDependsOn(@Nullable String... dependsOn);
String[] getDependsOn();
// 是否允许自动装配
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 设置是否主要bean
void setPrimary(boolean primary);
boolean isPrimary();
// 工厂bean和工厂方法
void setFactoryBeanName(@Nullable String factoryBeanName);
String getFactoryBeanName();
void setFactoryMethodName(@Nullable String factoryMethodName);
String getFactoryMethodName();
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
// 使用setter注入时的key-value对,都保存在这里
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// @since 5.1初始化方法和销毁方法
void setInitMethodName(@Nullable String initMethodName);
String getInitMethodName();
void setDestroyMethodName(@Nullable String destroyMethodName);
String getDestroyMethodName();
// 为bean设置角色
void setRole(int role);
int getRole();
// bean的描述
void setDescription(@Nullable String description);
String getDescription();
// 返回此bean定义的可解析类型,基于bean类或其他特定元数据。
// 这通常在运行时合并bean定义上完全解决但不一定是在配置时定义实例上。
ResolvableType getResolvableType();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
}
2、AbstractBeanDefinition
该类对通用核心方法完成了实现(这也是抽象类的作用),同时对一些成员变量提供了默认值:
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// 定义一些常量
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;
// ...还有很多
// 初始化默认值
private volatile Object beanClass;
private String scope = SCOPE_DEFAULT
private boolean autowireCandidate = true;
private boolean primary = false;
// ...还有很多
// 构造器
protected AbstractBeanDefinition() {
this(null, null);
}
// 指定构造器参数和属性参数
protected AbstractBeanDefinition(@Nullable ConstructorArgumentValues cargs, @Nullable MutablePropertyValues pvs) {
this.constructorArgumentValues = cargs;
this.propertyValues = pvs;
}
// 使用深拷贝创建一个新的
protected AbstractBeanDefinition(BeanDefinition original) {
}
// 复制一个bean的定义到当前bean,通常父子bean合并时可用
public void overrideFrom(BeanDefinition other) {
}
// ...此处省略其他的方法实现
}
3、GenericBeanDefinition
该类实现比较简单,提供了设置父子关系和构建实例的方法,该类及其子类是目前版本使用最多的BeanDefinition:
public class GenericBeanDefinition extends AbstractBeanDefinition {
@Nullable
private String parentName;
public GenericBeanDefinition() {
super();
}
// 通过深拷贝创建一个bean
public GenericBeanDefinition(BeanDefinition original) {
super(original);
}
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
@Override
@Nullable
public String getParentName() {
return this.parentName;
}
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
return new GenericBeanDefinition(this);
}
}
此时,我们可以编写如下的测试用例:
@Test
public void testGenericBeanDefinition(){
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName("com.ydlclass.User");
// 此处类似setter注入的描述
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.addPropertyValue("name","lily");
propertyValues.addPropertyValue("age",12);
beanDefinition.setPropertyValues(propertyValues);
}
注:这个测试用例及其简单,但是他却可以使用字符串的形式描述一切的类。
我们再测试一种具有继承关系的bean:
public class Dog {
private String color;
private Integer age;
}
public class TeddyDog extends Dog{
private String name;
}
xml可以如下定义:
<bean id="dog" class="com.ydlclass.Dog">
<property name="color" value="white"/>
<property name="age" value="3"/>
</bean>
<bean id="teddyDog" class="com.ydlclass.TeddyDog" parent="dog">
<property name="name" value="小红"/>
</bean>
如果是手动定义如下:
@Test
public void testRootBeanDefinition() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
RootBeanDefinition dog = new RootBeanDefinition();
dog.setBeanClassName("com.ydlclass.Dog");
BeanMetadataAttribute color = new BeanMetadataAttribute("color","white");
BeanMetadataAttribute age = new BeanMetadataAttribute("age","3");
dog.addMetadataAttribute(color);
dog.addMetadataAttribute(age);
// 子Definition的创建需要依赖父Definition
ChildBeanDefinition teddy = new ChildBeanDefinition("dog");
teddy.setBeanClassName("com.ydlclass.TeddyDog");
BeanMetadataAttribute name = new BeanMetadataAttribute("name","nanls");
teddy.addMetadataAttribute(name);
}
GenericBeanDefinition在很多场景可以替换以上的内容,但是由于历史等原因,RootBeanDefinition依旧存在而且很重要,后期的归一处理还是要将不同的BeanDefinition转换或合并至一个RootBeanDefinition:
- RootBeanDefinition与AbstractBeanDefinition是互补关系,RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性。
- RootBeanDefinition不能有父BeanDefinition,可以和ChildBeanDefinition配合使用构建父子关系(bean是可以继承的)。
- 目前最常用的BeanDefinition是GenericBeanDefinition及其子类的实现,GenericBeanDefinition很强大,也可以很轻松的独立的构建父子关系。
- 有时为了统一调用,不同的BeanDefinition可以合并、拷贝等。
// 转换的
GenericBeanDefinition definition = new GenericBeanDefinition(teddy);
// 合并的
definition.overrideFrom(dog);