Spring源码之BeanDefinition
2021-01-23 01:15
标签:hash 优先 返回 inf 12c dfa serial date nbsp 不废话,直接看源码 BeanDefinition描述了一个bean实例 这是一个小的接口:主要目的是允许BeanFactoryPostProcessor和PropertyPlaceholderConfigurer修改属性值和其他bean元数据。 先来看接口上标注的这段 翻译下来就是: 这个接口为从其它任意类中获取或设置元数据提供了一个通用的规范。 其实这就是 我们再来看这个接口中定义的方法: 就是提供了一些属性跟设置属性的方法 那么现在问题来了,在我们整个 译:这个接口提供了一个方法去获取配置源对象,其实就是我们的原文件。 这个接口只提供了一个方法: 我们可以理解为,当我们通过注解的方式定义了一个 如果我们通过 为什么需要 对比 这是因为 例如: 这样可以方便我们创建其子类,如我们接下来要讲的: 我们在上文中已经提到过, 可以看到,在这个类中,维护了一个map,这就是 这个类主要就是对我们上面的map中的数据操作做了更深一层的封装,我们就看其中的两个方法: 可以发现,它只是将属性统一封装成了一个 我们的 这里说的属性仅仅指的是 替代了原来的 我们通过注解配置的bean以及我们的配置类(除 现在已经被 Spring在启动时会实例化几个初始化的 Spring在合并 我们通过 这个接口继承了我们的 这个接口相比于 通过形如下面的API注册的bean都是 这里的 通过 通过注解扫描的类,如 通过 我们来看官网上的一段介绍: 大概翻译如下: 一个 一个子 使用 想到了什么,多态对吧 我们通过一个例子来观察下合并发生了什么,编写一个Demo如下: 实体类 运行: 在上面的例子中,我们将 但是我们在配置文件中并没有直接设置 但是在最后运行结果,我们可以发现, 也就是说,子 另外, 也就是说,子 所以我们可以总结如下: 子 这个过程中,子 另外我们需要注意的是: 1.子 2.子 以我们上面的demo为例,我们在父 因为子 关于 1.并不是作为父 2.如果一个 那么必须要设置其 3. Spring源码之BeanDefinition 标签:hash 优先 返回 inf 12c dfa serial date nbsp 原文地址:https://www.cnblogs.com/lusaisai/p/12885851.html
BeanDefinition
是什么?先看一下继承关系:
1.
BeanDefinition
继承的接口:AttributeAccessor
/**
* Interface defining a generic contract for attaching and accessing metadata
* to/from arbitrary objects.
* @author Rob Harrop
* @since 2.0
*/
public interface AttributeAccessor {
访问者
模式的一种体现,采用这方方法,我们可以将数据接口跟操作方法进行分离。void setAttribute(String name, @Nullable Object value);
Object getAttribute(String name);
Object removeAttribute(String name);
boolean hasAttribute(String name);
String[] attributeNames();
BeanDefiniton
体系中,这个被操作的数据结构在哪呢?不要急,在后文中的AbstractBeanDefinition
会介绍2.
BeanDefinition
继承的接口:BeanMetadataElement/**
* Interface to be implemented by bean metadata elements
* that carry a configuration source object.
*
* @author Juergen Hoeller
* @since 2.0
*/
public interface BeanMetadataElement {
/**
* Return the configuration source {@code Object} for this metadata element
* (may be {@code null}).
*/
@Nullable
Object getSource();
IndexService
时,那么此时的IndexService
对应的BeanDefinition
通过getSource
方法返回的就是IndexService.class
这个文件对应的一个File
对象。@Bean
方式定义了一个IndexService
的话,那么此时的source是被@Bean
注解所标注的一个Mehthod
对象。3.
AbstractBeanDefinition
:public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
...
}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
等等AttributeAccerror
AttributeAccerror
采用了访问者的涉及模式,将数据结构跟操作方法进行了分离,数据结构在哪呢?就在AttributeAccessorSupport
这个类中,我们看下它的代码:public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {
/** Map with String keys and Object values. */
private final Map
BeanDefinition
体系中,通过访问者模式
所有操作的数据对象。BeanMetadataAttributeAccessor
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
的三个子类
GenericBeanDefinition
:ChildBeanDefinition
,比起ChildBeanDefinition
更为灵活,ChildBeanDefinition
在实例化的时候必须要指定一个parentName
,而GenericBeanDefinition
不需要。@Bena
外)的BeanDefiniton
类型都是GenericBeanDefinition
。
ChildBeanDefinition
:GenericBeanDefinition
所替代了。我在5.1.x
版本没有找到使用这个类的代码。RootBeanDefinition
BeanDefinition
,这几个BeanDefinition
的类型都为RootBeanDefinition
BeanDefinition
返回的都是RootBeanDefinition
@Bean
注解配置的bean,解析出来的BeanDefinition
都是RootBeanDefinition
(实际上是其子类ConfigurationClassBeanDefinition
)AnnotatedBeanDefinition
BeanDefinition
接口,我们查看其源码可以发现:AnnotationMetadata getMetadata();
@Nullable
MethodMetadata getFactoryMethodMetadata();
BeanDefinition
, 仅仅多提供了两个方法getMetadata()
,主要用于获取注解元素据。从接口的命名上我们也能看出,这类主要用于保存通过注解方式定义的bean所对应的BeanDefinition
。所以它多提供了一个关于获取注解信息的方法getFactoryMethodMetadata()
,这个方法跟我们的@Bean
注解相关。当我们在一个配置类中使用了@Bean
注解时,被@Bean
注解标记的方法,就被解析成了FactoryMethodMetadata
。
AnnotatedBeanDefinition
的三个实现类
AnnotatedGenericBeanDefinition
:AnnotatedGenericBeanDefinition
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();
ac.register(Config.class);
}
config
对象,最后在Spring容器中就是一个AnnotatedGenericBeanDefinition
。@Import
注解导入的类,最后都是解析为AnnotatedGenericBeanDefinition
。
ScannedGenericBeanDefinition
:@Service
,@Compent
等方式配置的Bean都是ScannedGenericBeanDefinition
ConfigurationClassBeanDefinition
:@Bean
的方式配置的Bean为ConfigurationClassBeanDefinition
什么是合并?
BeanDefinition
包含了很多的配置信息,包括构造参数,setter方法的参数还有容器特定的一些配置信息,比如初始化方法,静态工厂方法等等。BeanDefinition
可以从它父BeanDefinition
继承配置信息,不仅如此,还可以覆盖其中的一些值或者添加一些自己需要的属性。BeanDefinition
的父子定义可以减少很多的重复属性的设置,父BeanDefinition
可以作为BeanDefinition
定义的模板。public class DerivedTestBean {
private String name;
private int age;
// 省略getter setter方法
}
public class TestBean {
private String name;
private String age;
// 省略getter setter方法
}
public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("application.xml");
DerivedTestBean derivedTestBean = (DerivedTestBean) cc.getBean("child");
System.out.println("derivedTestBean的name = " + derivedTestBean.getName());
System.out.println("derivedTestBean的age = " + derivedTestBean.getAge());
}
}
derivedTestBean的name = override
derivedTestBean的age = 1
DerivedTestBean
的parent
属性设置为了parent
,指向了我们的TestBean
,同时将TestBean
的age属性设置为1,DerivedTestBean
的age属性。DerivedTestBean
中的age属性已经有了值,并且为1,就是我们在其parent Bean(也就是TestBean
)中设置的值。BeanDefinition
会从父BeanDefinition
中继承没有的属性。DerivedTestBean
跟TestBean
都指定了name属性,但是可以发现,这个值并没有被覆盖掉,BeanDefinition
中已经存在的属性不会被父BeanDefinition
中所覆盖。合并的总结:
BeanDefinition
会从父BeanDefinition
中继承没有的属性BeanDefinition
中已经存在的属性不会被父BeanDefinition
中所覆盖关于合并需要注意的点:
BeanDefinition
中的class
属性如果为null,同时父BeanDefinition
又指定了class
属性,那么子BeanDefinition
也会继承这个class
属性。BeanDefinition
必须要兼容父BeanDefinition
中的所有属性。这是什么意思呢?BeanDefinition
中指定了name跟age属性,但是如果子BeanDefinition
中子提供了一个name的setter方法,这个时候Spring在启动的时候会报错。BeanDefinition
不能承接所有来自父BeanDefinition
的属性BeanDefinition
中abstract
属性的说明:BeanDefinition
就一定要设置abstract
属性为true,abstract
只代表了这个BeanDefinition
是否要被Spring进行实例化并被创建对应的Bean,如果为true,代表容器不需要去对其进行实例化。BeanDefinition
被当作父BeanDefinition
使用,并且没有指定其class
属性。abstract
为trueabstract=true
一般会跟父BeanDefinition
一起使用,因为当我们设置某个 BeanDefinition
的abstract=true
时,一般都是要将其当作BeanDefinition
的模板使用,否则这个BeanDefinition
也没有意义,除非我们使用其它BeanDefinition
来继承它的属性
文章标题:Spring源码之BeanDefinition
文章链接:http://soscw.com/index.php/essay/45682.html