BeanDefinition是什么?
我们先看官网上是怎么解释的:
从上文中,我们可以得出以下几点结论:
- BeanDefinition包含了我们对bean做的配置,比如XML<bean/>标签的形式进行的配置
- 换而言之,Spring将我们对bean的定义信息进行了抽象,抽象后的实体就是BeanDefinition,并且Spring会以此作为标准来对Bean进行创建
- BeanDefinition包含以下元数据:
- 一个全限定类名,通常来说,就是对应的bean的全限定类名。
- bean的行为配置元素,这些元素展示了这个bean在容器中是如何工作的包括scope(域,我们文末有简单介绍),lifecycle callbacks(生命周期回调,下篇文章介绍)等等
- 这个bean的依赖信息
- 一些其他配置信息,比如我们配置了一个连接池对象,那么我们还会配置它的池子大小,最大连接数等等
在这里,我们来比较下,正常的创建一个bean,跟Spring通过抽象出一个BeanDefinition来创建bean有什么区别:
正常的创建一个java bean:
Spring通过BeanDefinition来创建bean:
通过上面的比较,我们可以发现,相比于正常的对象的创建过程,Spring对其管理的bean没有直接采用new的方式,而是先通过解析配置数据以及根据对象本身的一些定义而获取其对应的beandefinition,并将这个beandefinition作为之后创建这个bean的依据。同时Spring在这个过程中提供了一些扩展点,例如我们在图中所提到了BeanfactoryProcessor。这些大家先作为了解,之后在源码阶段我们再分析。
BeanDefinition的方法分析
这里对于每个字段我只保留了一个方法,只要知道了字段的含义,方法的含义我们自然就知道了
// 获取父BeanDefinition,主要用于合并,下节中会详细分析 String getParentName(); // 对于的bean的ClassName void setBeanClassName(@Nullable String beanClassName); // Bean的作用域,不考虑web容器,主要两种,单例/原型,见官网中1.5内容 void setScope(@Nullable String scope); // 是否进行懒加载 void setLazyInit(boolean lazyInit); // 是否需要等待指定的bean创建完之后再创建 void setDependsOn(@Nullable String... dependsOn); // 是否作为自动注入的候选对象 void setAutowireCandidate(boolean autowireCandidate); // 是否作为主选的bean void setPrimary(boolean primary); // 创建这个bean的类的名称 void setFactoryBeanName(@Nullable String factoryBeanName); // 创建这个bean的方法的名称 void setFactoryMethodName(@Nullable String factoryMethodName); // 构造函数的参数 ConstructorArgumentValues getConstructorArgumentValues(); // setter方法的参数 MutablePropertyValues getPropertyValues(); // 生命周期回调方法,在bean完成属性注入后调用 void setInitMethodName(@Nullable String initMethodName); // 生命周期回调方法,在bean被销毁时调用 void setDestroyMethodName(@Nullable String destroyMethodName); // Spring可以对bd设置不同的角色,了解即可,不重要 // 用户定义 int ROLE_APPLICATION = 0; // 某些复杂的配置 int ROLE_SUPPORT = 1; // 完全内部使用 int ROLE_INFRASTRUCTURE = 2; void setRole(int role); // bean的描述,没有什么实际含义 void setDescription(@Nullable String description); // 根据scope判断是否是单例 boolean isSingleton(); // 根据scope判断是否是原型 boolean isPrototype(); // 跟合并beanDefinition相关,如果是abstract,说明会被作为一个父beanDefinition,不用提供class属性 boolean isAbstract(); // bean的源描述,没有什么实际含义 String getResourceDescription(); // cglib代理前的BeanDefinition BeanDefinition getOriginatingBeanDefinition();
BeanDefinition的继承关系
类图如下:
1.BeanDefinition继承的接口
org.springframework.core.AttributeAccessor
先来看接口上标注的这段java doc
Interface defining a generic contract for attaching and accessing metadata to/from arbitrary objects.
翻译下来就是:
这个接口为从其它任意类中获取或设置元数据提供了一个通用的规范。
其实这就是访问者模式的一种体现,采用这方方法,我们可以将数据接口跟操作方法进行分离。
我们再来看这个接口中定义的方法:
void setAttribute(String name, @Nullable Object value); Object getAttribute(String name); Object removeAttribute(String name); boolean hasAttribute(String name); String[] attributeNames();
就是提供了一个获取属性跟设置属性的方法
那么现在问题来了,在我们整个BeanDefiniton体系中,这个被操作的数据结构在哪呢?不要急,在后文中的AbstractBeanDefinition会介绍。
- org.springframework.beans.BeanMetadataElement
我们还是先看java doc:
Interface to be implemented by bean metadata elements that carry a configuration source object.
翻译:这个接口提供了一个方法去获取配置源对象,其实就是我们的原文件。
这个接口只提供了一个方法:
@Nullable Object getSource();
我们可以理解为,当我们通过注解的方式定义了一个IndexService时,那么此时的IndexService对应的BeanDefinition通过getSource方法返回的就是IndexService.class这个文件对应的一个File对象。
如果我们通过@Bean方式定义了一个IndexService的话,那么此时的source是被@Bean注解所标注的一个Mehthod对象。
2.AbstractBeanDefinition
AbstractBeanDefinition的继承关系
先看一下类图:
- org.springframework.core.AttributeAccessorSupport
可以看到这个类实现了AttributeAccerror接口,我们在上文中已经提到过,AttributeAccerror采用了访问者的涉及模式,将数据结构跟操作方法进行了分离,数据结构在哪呢?就在AttributeAccessorSupport这个类中,我们看下它的代码:
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); } public BeanMetadataAttribute getMetadataAttribute(String name) { return (BeanMetadataAttribute) super.getAttribute(name); }
可以发现,它只是将属性统一封装成了一个BeanMetadataAttribute,然后就调用了父类的方法,将其放入到map中。
我们的AbstractBeanDefinition通过继承了BeanMetadataAttributeAccessor这个类,可以对BeanDefinition中的属性进行操作。这里说的属性仅仅指的是BeanDefinition中的一个map,而不是它的其它字段。
为什么需要AbstractBeanDefinition?
对比BeanDefinition的源码我们可以发现,AbstractBeanDefinition对BeanDefinition的大部分方法做了实现(没有实现parentName相关方法)。同时定义了一系列的常量及默认字段。这是因为BeanDefinition接口过于顶层,如果我们依赖BeanDefinition这个接口直接去创建其实现类的话过于麻烦,所以通过AbstractBeanDefinition做了一个下沉,并给很多属性赋了默认值,例如
// 默认情况不是懒加载的 private boolean lazyInit = false; // 默认情况不采用自动注入 private int autowireMode = AUTOWIRE_NO; // 默认情况作为自动注入的候选bean private boolean autowireCandidate = true; // 默认情况不作为优先使用的bean private boolean primary = false; ........
这样可以方便我们创建其子类,如我们接下来要讲的ChildBeanDefinition,RootBeanDefinition等等