Beandefinition是什么?
我们先来看官网是怎么解释的?
从上文中我们可以得出以下几点结论:
1、Beandefinition包含了我们对bean做的配置,比如XML<bean/>标签的形式进行配置
2、换言之,spring将我们对bean的定义信息进行了抽象,抽象后的实体就是beanDefinition,并且spring会以此作为标准来对bean进行创建
3、Beandefinition包含以下元数据:
3.1、一个全限定类名,通常来说,就是对应的bean的全限定类名
3.2、bean的行为配置信息,这些元素展示了这个bean在容器中是如何工作的包括scope、lifecycle、callback生命周期回调等等
3.3、这个bean的依赖配置信息
3.4、一些其他配置信息,比如我们配置了一个连接池大小,最大连接数等等
在这里,我们来对比一下,正常创建一个bean,跟spring抽象出来一个beandefinition创建bean有什么区别:
正常的创建一个bean
spring创建一个bean的过程
通过上面的比较,我们可以发现,相比于正常的对象的创建过程,Spring对其管理的bean没有直接采用new的方式,而是先通过解析配置数据以及根据对象本身的一些定义而获取其对应的beandefinition,并将这个beandefinition作为之后创建这个bean的依据。同时Spring在这个过程中提供了一些扩展点,例如我们在图中所提到了bean工厂后置处理器。这些大家先作为了解,之后在源码阶段我们再分析。
BeanDefinition的方法分析
这里对于每个字段只保留了一个方法,只要知道字段的含义,方法的含义我们自然就知道了。
int ROLE_APPLICATION = 0; // 表示用户定义的bean
int ROLE_SUPPORT = 1; // 暂时没发现哪里用到了
int ROLE_INFRASTRUCTURE = 2; // 表示框架层面的基础bean
String getParentName();//获取父类BeanDefinition,主要用于合并
void setBeanClassName(@Nullable String beanClassName);//对于bean的className
void setScope(@Nullable String scope);//bean的作用域,不考虑web 只有单例和原型
void setLazyInit(boolean lazyInit);//懒加载
void setDependsOn(@Nullable String... dependsOn);//是否需要等待执行的bean创建完后再创建
void setAutowireCandidate(boolean autowireCandidate);//是否作为自动注入的候选对象
void setPrimary(boolean primary);//是否是主选的bean tie-breaker:平局决胜,也就是在平局的时候选出来的胜利者
* Java在进行自动注入时,如果找到了多个可注入bean,那么则选择被Primary标记的bean.
void setFactoryBeanName(@Nullable String factoryBeanName);//工厂bean名字,可以通过该bean中的某个方法得到一个bean对象
void setFactoryMethodName(@Nullable String factoryMethodName);//工厂方法,可以是某个实例的方法(和factoryBean配合使用),也可以是静态方法
ConstructorArgumentValues getConstructorArgumentValues();//构造方法参数值
MutablePropertyValues getPropertyValues();//属性值
void setInitMethodName(@Nullable String initMethodName);//初始化方法
void setDestroyMethodName(@Nullable String destroyMethodName);//销毁回调方法
void setRole(int role);//标志当前bean是用户创建的,还是基础框架中的
void setDescription(@Nullable String description);//人类可以看懂的描述
ResolvableType getResolvableType();//用来解析一个Bean对应的类型上的各种信息,比如泛型
boolean isAbstract();//跟合并的beanDefinition相关,如果是abstract,说明会被作为一个父BeanDefinition,不提供class属性
BeanDefinition getOriginatingBeanDefinition();//cglib代理前的beanDefinition
Beandefinition的继承关系
1、beandefinition继承的接口
org.springframework.core.AttributeAccessor
我们来看一下这个接口ijavadoc
Interface defining a generic contract for attaching and accessing metadatato/from arbitrary objects.
翻译下就是:
这个接口为从其它任意类中获取和设置元数据提供了一个通用的规范。
其实这就是访问者模式的一种体现,采用这方方法我们可以将数据接口和操作方法进行分离。
我们再来看下这个接口定义的方法
void setAttribute(String name, @Nullable Object value);
Object getAttribute(String name);
Object removeAttribute(String name);
boolean hasAttribute(String name);
String[] attributeNames();
就提供了一个获取属性和设置属性的方法。
那么问题来了,我们在整个beanDefinion体系中,这个被操作的数据结构在哪呢?不要急,我们在后文中AbstractBeanDefinition会介绍。
org.springframework.beans.BeanMetadataElement
我们来看一下javadoc
Interface to be implemented by bean metadata elements that carry a configuration source object.
翻译:这个接口提供了一个方法去获取配置源对象,其实就是我们的原文件。
这个接口只提供了一个方法
default Object getSource() {
return null;
}
我们可以理解为,当我们通过注解的方式定义一个IndexService时,那么此时的IndexService对应的beanDefinition通过getSource方法返回的就是IndexService.class这个文件对应的一个File对象。
2、AbstractBeanDefinition
AbstractBeanDefinition的继承关系,先看下类图
org.springframework.core.AttributeAccessorSupport
可以看到这个类实现了AttributeAccessor接口,我们在上文中已经提到过,AttributeAccessor采用的是访问者模式,将数据结构和操作方法进行了分离,数据结构在哪呢?就在这个类里面,我们来看下代码
public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {
/** Map with String keys and Object values. */
private final Map<String, Object> attributes = new LinkedHashMap<>();
@Override
public void setAttribute(String name, @Nullable Object value) {
Assert.notNull(name, "Name must not be null");
if (value != null) {
this.attributes.put(name, value);
}
else {
removeAttribute(name);
}
}
......//省略下面代码
可以看到,这个类中维护了一个map,这就是BeanDefinition体系中,通过访问者模式所有操作的数据对象。
org.springframework.beans.BeanMetadataAttributeAccessor
这个类主要是对我们上面的map做更深一层的封装,我们就看其中的几个方法
public void addMetadataAttribute(BeanMetadataAttribute attribute) {
super.setAttribute(attribute.getName(), attribute);
}
@Nullable
public BeanMetadataAttribute getMetadataAttribute(String name) {
return (BeanMetadataAttribute) super.getAttribute(name);
}
可以发现,它只是将属性封装成一个BeanMetadataAttribute,然后调用父类的方法放入map中。
为什么需要AbstractBeanDefinition?
对比Beandefinition的源码我们可以发现,AbstractBeanDefinition对BeanDefinition的大部分方法做了实现(没有实现parentName相关方法)。同时定义了一系列的常量和默认字段。这是因为BeanDefinition这个接口太过顶层。如果我们依赖这个接口去创建实现类的话太过麻烦,所以通过AbstractBeanDefinition做了一个下沉,并给很多属性赋值默认值。例如:
// 默认情况不是懒加载的
private boolean lazyInit = false;
// 默认情况不采用自动注入
private int autowireMode = AUTOWIRE_NO;
// 默认情况作为自动注入的候选bean
private boolean autowireCandidate = true;
// 默认情况不作为优先使用的bean
private boolean primary = false;
这样可以方便我们创建子类,如我们接下来讲的ChildBeanDefinition,RootBeanDefinition等等。
AbstractBeanDefinition三个子类
org.springframework.beans.factory.support.GenericBeanDefinition
替代了原来的ChildBeanDefinition,比起ChildBeanDefinition更加灵活,ChildBeanDefinition在实例化中必须指定一个parentName,而GenericBeanDefinition不需要,我们通过注解配置的bean以及我们的配置类(除@bean外)的beanDefinition都是GenericBeanDefinition。
org.springframework.beans.factory.support.ChildBeanDefinition
看一下javadoc
* Bean definition for beans which inherit settings from their parent.
* Child bean definitions have a fixed dependency on a parent bean definition.
*
* <p>A child bean definition will inherit constructor argument values,
* property values and method overrides from the parent, with the option
* to add new values. If init method, destroy method and/or static factory
* method are specified, they will override the corresponding parent settings.
* The remaining settings will <i>always</i> be taken from the child definition:
* depends on, autowire mode, dependency check, singleton, lazy init.
*
* <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.
2.5之后首选GenericBeanDefinition去创建
org.springframework.beans.factory.support.RootBeanDefinition
spring在启动的时候会初始化几个BeanDefinition,这几个BeanDefinition都是RootBeanDefinition类型的。
spring在合并BeanDefinition返回的都是BeanDefinition。
我们通过@Bean注解配置的bean,解析出来的beanDefinition都是RootBeanDefinition(实际上是其子类ConfigurationClassBeanDefinition)
4、AnnotatedBeanDefinition
这个接口继承了BeanDefinition我们查看源码可以发现
AnnotationMetadata getMetadata();
MethodMetadata getFactoryMethodMetadata();
相比于BeanDefinition多了两个方法
getMetadata()这个方法主要用于获取注解元数据,从接口的我们也能看出,这个类主要用于保存通过注解方法定义的beanDefinition,所以它提供了一个获取注解信息的方法
getFactoryMethodMetadata()这个方法跟我们@Bean注解相关,当我们在一个配置类中使用了@Bean注解时,被@Bean注解标记的方法,就被解析成了FactoryMethodMetadata
5、AnnotatedBeanDefinition的三个实现类
org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(AppConfig.class);
}
这里的config对象,最后在spring容器就是一个AnnotatedGenericBeanDefinition
通过@import注解导入的类,最后都是解析为AnnotatedGenericBeanDefinition
org.springframework.context.annotation.ScannedGenericBeanDefinition
通过注解扫描的类,如@service @co’mpent等方式配置的bean都是ScannedGenericBeanDefinition。
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.ConfigurationClassBeanDefinition
通过@Bean方式配置的bean都是ConfigurationClassBeanDefinition这个类型的
最后,我们还剩一个ClassDerivedBeanDefinition,这个类跟kotlin相关的类,笔者也不熟,这里就不做说明。
efinition。
org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.ConfigurationClassBeanDefinition
通过@Bean方式配置的bean都是ConfigurationClassBeanDefinition这个类型的
最后,我们还剩一个ClassDerivedBeanDefinition,这个类跟kotlin相关的类,笔者也不熟,这里就不做说明。