Spring源码系列(三)BeanDefinition(二)

1.写在前面

在上篇博客《Spring源码系列(二)BeanDefinition(一)》我们大概的介绍了下BeanDefinition接口中的一些属性,还有两个BeanDefinition的父接口。同时简单的介绍了下对应的实现类AbstractBeanDefinition。但是还有些属性没有介绍,这篇博客会把这些属性介绍了,同时会介绍一下BeanDefinition接口的一些实现类。还是那句话,Spring创建Bean都是根据这个BeanDefinition来的,所以要搞懂Spring的源码,必须要搞懂这些常用的BeanDefinition的实现类

2.BeanDefinition的一些常用属性

这节主要讲下上节博客中,没有介绍完的BeanDefinition的属性。例如ConstructorArgumentValuesMutablePropertyValuesparentName等属性。我们再来看下BeanDefinition的接口,具体的代码如下:

package org.springframework.beans.factory.config;

import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.core.AttributeAccessor;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

  //单例
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

  //原型
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

	int ROLE_APPLICATION = 0;

	int ROLE_SUPPORT = 1;

	int ROLE_INFRASTRUCTURE = 2;

	void setParentName(@Nullable String parentName);

	@Nullable
	String getParentName();

  //设置Bean的类名
	void setBeanClassName(@Nullable String beanClassName);

  //获取Bean的类名
	@Nullable
	String getBeanClassName();

  //设置作用域
	void setScope(@Nullable String scope);

  //获取对应的作用域
	@Nullable
	String getScope();

  //设置为懒加载
	void setLazyInit(boolean lazyInit);

  //判断是否是懒加载
	boolean isLazyInit();

  //设置DependOn,对应的DependOn注解,或者是XML中的配置的
	void setDependsOn(@Nullable String... dependsOn);

  //获取DependOn设置的值
	@Nullable
	String[] getDependsOn();

  //自动装配的候选的对象
	void setAutowireCandidate(boolean autowireCandidate);

  //是否是自动装配的候选对象
	boolean isAutowireCandidate();

  //设置主要的注入的对象
	void setPrimary(boolean primary);

  //获取是否主要的注入对象
	boolean isPrimary();

  //设置工厂Bean的名称
	void setFactoryBeanName(@Nullable String factoryBeanName);

  //获取工厂Bean的名称
	@Nullable
	String getFactoryBeanName();

  //设置工厂方法的名称
	void setFactoryMethodName(@Nullable String factoryMethodName);

  //获取工厂方法的名称
	@Nullable
	String getFactoryMethodName();

  //获取构造器的参数的值
	ConstructorArgumentValues getConstructorArgumentValues();
	
  //是否构造器参数有值
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

  //获取属性
	MutablePropertyValues getPropertyValues();

  //是否有属性
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

  //设置对应的初始化方法
	void setInitMethodName(@Nullable String initMethodName);

  //获取对应的初始化方法
	@Nullable
	String getInitMethodName();

  //设置对应的销毁的方法
	void setDestroyMethodName(@Nullable String destroyMethodName);

  //获取对应的销毁的方法
	@Nullable
	String getDestroyMethodName();

	void setRole(int role);

	int getRole();

  //设置对应的描述信息
	void setDescription(@Nullable String description);

  //获取对应的描述信息
	@Nullable
	String getDescription();

	ResolvableType getResolvableType();

  //判断是否是单例
	boolean isSingleton();

  //判断是否是原型
	boolean isPrototype();

  //判断是否是抽象
	boolean isAbstract();

  //获取源的描述信息
	@Nullable
	String getResourceDescription();
  
  //返回原始的BeanDefinition
	@Nullable
	BeanDefinition getOriginatingBeanDefinition();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140

2.1ConstructorArgumentValues与MutablePropertyValues

这两个属性,主要对应的xml中两个标签、。我们通过配置xml的方式,将一个bean配置好,同时指定了前面的两个标签。然后创建ClassPathXmlApplicationContext类获取对应BeanFactory,然后通过BeanFactory获取对应BeanDefinition信息,然后打印出来这两个属性。具体的代码如下:

package com.ys.beanDefinition.constructorOrProperty;

public class A {
    private String name;
    private String age;

    public A() {
    }

    public A(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="a" class="com.ys.beanDefinition.constructorOrProperty.A">
        <constructor-arg name="name" value="小明"/>
        <constructor-arg name="age" value="18"/>
        <property name="name" value="张三"/>
        <property name="age" value="19"/>
    </bean>

</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
package com.ys.beanDefinition.constructorOrProperty;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) {
        ClassPathXmlApplicationContext xmlApplicationContext = new ClassPathXmlApplicationContext("SpringConstructorOrProperty.xml");
        BeanDefinition aBeanDefinition = xmlApplicationContext.getBeanFactory().getBeanDefinition("a");
        System.out.println("ArgumentCount:" + aBeanDefinition.getConstructorArgumentValues().getArgumentCount());
        System.out.println("PropertyValue:" + aBeanDefinition.getPropertyValues());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

运行的结果如下:

Spring源码系列(三)BeanDefinition(二)

可以看的对应的参数已经填充进去了。但是这两个参数返回的类型是ConstructorArgumentValuesMutablePropertyValues。这个两个类型我们有必要看下,具体的代码如下:

private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<>();
private final List<ValueHolder> genericArgumentValues = new ArrayList<>();
  • 1
  • 2

可以看到对应是两个集合用来存构造参数中的值,一个是Map,一个是List,两个集合中存的都是ValueHolder,那为什么要用两个集合呢?ValueHolder又是什么呢?

先来回答第一个问题,为什么有两个集合,因为标签中可以按照index(索引)来存构造参数的值。具体的例子如下:

<constructor-arg name="name" value="小明" index="1"/>
<constructor-arg name="age" value="18" index="0"/>
  • 1
  • 2

所有有了两个集合,其中Map的键存的是索引,而没有配置索引的就直接存到List集合中去。

再来回答第二个问题,ValueHolder又是什么呢?我们可以直接看下ValueHolder的源码,具体如下:

//对应标签中value的值
@Nullable
private Object value;

//对应标签中type的值
@Nullable
private String type;

//对应标签中name的值
@Nullable
private String name;

//原属性
@Nullable
private Object source;

//是否已转换
private boolean converted = false;

//要转换的属性
@Nullable
private Object convertedValue;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

上面的属性可能都比较好懂,但是有一个转换的属性,可能不太好懂。这儿其实就是对应标签中ref属性,因为有的时候需要转换对应的属性。

看完了ConstructorArgumentValues我们再来看下MutablePropertyValues,具体的代码如下:

//存的是标签中的属性
private final List<PropertyValue> propertyValueList;

//已经处理好的属性
@Nullable
private Set<String> processedProperties;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看到List集合中存了一个PropertyValue类型的值,我们去代码中看看其中有哪些属性,具体的代码如下:

//对应标签中的name
private final String name;

//对应标签中的value
@Nullable
private final Object value;

//optional属性
private boolean optional = false;

//是否已经转换
private boolean converted = false;

//转换后的值
@Nullable
private Object convertedValue;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

可以发现是对对应的标签中的属性,进行了一系列的包装。和上面的ValueHolder有异曲同工之妙。

2.2ResourceDescription与Description

这两个都是描述信息,一个描述的是源文件,一个是描述类,由于这个比较简单,笔者就不做详细介绍了。只需要加上一个@Description(“描述信息”)既可以。

3.BeanDefinition的分类

要搞清楚分类,我们必须了解的BeadDefinition的常用的一些实现类。具体的结构图如下:

Spring源码系列(三)BeanDefinition(二)

上篇博客中我们已经介绍了AbstractBeanDefinition,它主要是对BeanDefinition一些简单的实现,和对BeanDefinition的两个接口进行了相应的实现,但是这个类是个抽象,无法实例化。同时对一些相同的属性和方法进行了抽象,其他的实现类主要实现最主要的部分就行了。通过上图我们可以看到直接继承AbstractBeanDefinition的类有三个,分别是RootBeanDefinitionChildBeanDefinitionGenericBeanDefinition我们先来介绍这个几个BeanDefinition

3.1RootBeanDefinitionChildBeanDefinition

打开对应的RootBeanDefinitionChildBeanDefinition代码,注释中有一句话,我们可以看看,具体的内容如下:

Spring源码系列(三)BeanDefinition(二)

Spring源码系列(三)BeanDefinition(二)

这句话的意思就是:从Spring 2.5开始,以编程方式注册Bean定义的首选方式是GenericBeanDefinition类,该类允许通过GenericBeanDefinitionsetParentName方法动态定义父依赖项。对于大多数用例,这有效地代替了RootBeanDefinitionChildBeanDefinition类。也就是这个两个类是Spring早期的产物。其中说到setParentName方法来动态定义父依赖项,这句话又是什么意思呢?

回答这个问题,就要回到了早期的Spring的编程方式。Spring早期的时候推荐是利用书写BeanDefinition的定义来进行编程。后面有了xml,才渐渐的利用xml配置BeanDefinition,再到后来的注解。那么上面的那句话又是什么意思呢?设想一下的场景,如果一个A的BeanDefinition和B的BeanDefinition,有一些相同的属性,在没有用xml情况下,你是不是写出了如下的代码:

package com.ys.beanDefinition.all;

import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        RootBeanDefinition aBeanDefinition = new RootBeanDefinition();
        aBeanDefinition.setBeanClass(A.class);
        aBeanDefinition.setLazyInit(false);

        RootBeanDefinition bBeanDefinition = new RootBeanDefinition();
        bBeanDefinition.setBeanClass(B.class);
        bBeanDefinition.setLazyInit(false);
        context.registerBeanDefinition("a",aBeanDefinition);
        context.registerBeanDefinition("b",bBeanDefinition);
        context.refresh();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

我们发现上面的代码创建了两个BeanDefinition。同时这两个BeanDefinition的的懒加载的属性都是false,假设我们现在有很多的BeanDefinition,而且他们当中有些属性都是一些,难道我们每写一个BeanDefinition都需要写这些重复的方法,我们难道不能使用一个模板的BeanDefinition来存这些相同的属性,然后让其他的BeanDefinition都继承这个BeanDefinition类,然后都会继承这些相同的属性。这个时候我们可能需要原来的父BeanDefinition不用创建出Bean,就是不希望设置BeanClass属性,因为它只作为一个模板,它不用创建的。如果不设置BeanClass属性,Spring容器在初始化话的时候为报错。具体的如下:

package com.ys.beanDefinition.all;

import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        RootBeanDefinition aBeanDefinition = new RootBeanDefinition();
        //aBeanDefinition.setBeanClass(A.class);
        aBeanDefinition.setLazyInit(false);

        RootBeanDefinition bBeanDefinition = new RootBeanDefinition();
        bBeanDefinition.setBeanClass(B.class);
        bBeanDefinition.setLazyInit(false);
        context.registerBeanDefinition("a",aBeanDefinition);
        context.registerBeanDefinition("b",bBeanDefinition);
        context.refresh();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

还是原来的代码,我们只不过将其中一行的代码注释掉了。然后运行的结果如下:

Spring源码系列(三)BeanDefinition(二)

会报创建a的时候报错了。这是由于没有设置对应的BeanClass属性,但是有的时候我们只需要父的BeanDefinition作为模块,它不需要创建,那么难道没有办法了吗?有办法,就是设置这个类为abstract的。具体的代码如下:

package com.ys.beanDefinition.all;

import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        RootBeanDefinition aBeanDefinition = new RootBeanDefinition();
        //aBeanDefinition.setBeanClass(A.class);
        aBeanDefinition.setAbstract(true);
        aBeanDefinition.setLazyInit(false);

        RootBeanDefinition bBeanDefinition = new RootBeanDefinition();
        bBeanDefinition.setBeanClass(B.class);
        bBeanDefinition.setLazyInit(false);
        context.registerBeanDefinition("a",aBeanDefinition);
        context.registerBeanDefinition("b",bBeanDefinition);
        context.refresh();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

运行的结果如下:

Spring源码系列(三)BeanDefinition(二)

可以发现我们的容器在创建的时候已经不报错了。我们已经完成了对应模板BeanDefinition的创建了。但是要怎么让其他的BeanDefinition继承这个模板BeanDefinition呢?从而获得相同的属性呢?这个时候就需要用到ChildBeanDefinition这个类。现在假设有以下的应用场景,所有的Bean的都是支持懒加载的。我们总不能给每一个BeanDefinition设置成懒加载为true吧!这个时候就需要用到我们的RootBeanDefinitionChildBeanDefinition组合场景了。具体的代码如下:

package com.ys.beanDefinition.all;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        //模板BeanDefinition
        RootBeanDefinition templateBeanDefinition = new RootBeanDefinition();
        Map<String, String> map = new HashMap<>();
        map.put("name", "king");
        templateBeanDefinition.setPropertyValues(new MutablePropertyValues(map));
        templateBeanDefinition.setAbstract(true);

        ChildBeanDefinition aChildBeanDefinition = new ChildBeanDefinition("template");
        aChildBeanDefinition.setBeanClass(A.class);

        ChildBeanDefinition bChildBeanDefinition = new ChildBeanDefinition("template");
        bChildBeanDefinition.setBeanClass(B.class);

        context.registerBeanDefinition("template", templateBeanDefinition);
        context.registerBeanDefinition("a", aChildBeanDefinition);
        context.registerBeanDefinition("b", bChildBeanDefinition);
        context.refresh();

        System.out.println("A:name:" + context.getBean(A.class).getName());
        System.out.println("B:name:" + context.getBean(B.class).getName());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

我们在A和B类中提供相同的属性,属性的名字都是name,然后我们创建了一个模板的BeanDefinition,然后通过两个ChildBeanDefinition分别将其中的parentName的属性设置成template,也就是我们的模板的BeanDefinition,然后在模板的BeanDefinition中设置了name的值,这个时候理论上两个ChildBeanDefinition中所创建的两个Beanname的值应该都是king,具体的运行结果如下:

Spring源码系列(三)BeanDefinition(二)

具体的结果正如我们猜测的那样,A和B中name的属性的值都为king。那么这儿merge(合并)的逻辑又是什么呢?后面的博客会讲。可能这个时候可能有读者会问既然有了这些,为什么还要有GenericBeanDefinition呢?这个时候就不得不说下RootBeanDefinitionChildBeanDefinition的缺点了。

其中RootBeanDefinition不能作为子BeanDefinition,具体的可以看下Spring的源码,具体的代码如下:

Spring源码系列(三)BeanDefinition(二)

我们可以看到Spring的源码直接将setParentName方法直接抛出了异常,所以RootBeanDefinition不能作为子的BeanDefinition,那可能有读者会问:为什么不能设置为子BeanDefinition?后面的博客会讲的。

同时ChildBeanDefinition为什么只能作为子BeanDefinition呢?我们直接看源码即可,具体的代码如下:

Spring源码系列(三)BeanDefinition(二)

我们可以看到所有的构造函数有都是要提供一个parentName的属性,所以它只能作为子BeanDefinition。所以在Spring2.5以后就出现了GenericBeanDefinition,就是为了解决这些问题。

3.2GenericBeanDefinition

字面上的意思就是通用的BeanDefinition。同时也是为了解决RootBeanDefinitionChildBeanDefinition上面提到的问题而出现的。GenericBeanDefinition既可以作为父BeanDefinition同时也能作为子BeanDefinition。下面我们可以写个例子证明一下,具体的代码如下:

package com.ys.beanDefinition.all;

import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

        //模板BeanDefinition
     	GenericBeanDefinition templateBeanDefinition = new GenericBeanDefinition();
        Map<String, String> map = new HashMap<>();
        map.put("name", "king");
        templateBeanDefinition.setPropertyValues(new MutablePropertyValues(map));
        templateBeanDefinition.setAbstract(true);

        GenericBeanDefinition aChildBeanDefinition = new GenericBeanDefinition();
        aChildBeanDefinition.setParentName("template");
        aChildBeanDefinition.setBeanClass(A.class);

        GenericBeanDefinition bChildBeanDefinition = new GenericBeanDefinition();
        bChildBeanDefinition.setParentName("template");
        bChildBeanDefinition.setBeanClass(B.class);

        context.registerBeanDefinition("template", templateBeanDefinition);
        context.registerBeanDefinition("a", aChildBeanDefinition);
        context.registerBeanDefinition("b", bChildBeanDefinition);
        context.refresh();

        System.out.println("A:name:" + context.getBean(A.class).getName());
        System.out.println("B:name:" + context.getBean(B.class).getName());
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

运行的结果如下:

Spring源码系列(三)BeanDefinition(二)

可以看到我们的运行的结果和前面的一样,同时这个GenericBeanDefinition既可以作为父的BeanDefinition,同时也可以作为子的BeanDefinition。那么这种方式在xml中又是怎么表示的呢?具体的代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="template" abstract="true">
        <property name="name" value="king"/>
    </bean>

    <bean class="com.ys.beanDefinition.abstractXml.A" parent="template" id="a"/>

</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
package com.ys.beanDefinition.abstractXml;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext xmlApplicationContext = new ClassPathXmlApplicationContext("SpringAbstract.xml");
        System.out.println("template:BeanDefinition:" + xmlApplicationContext.getBeanFactory().getBeanDefinition("template").getClass());
        System.out.println("A:BeanDefinition:" + xmlApplicationContext.getBeanFactory().getBeanDefinition("a").getClass());
        System.out.println("A:name:" + xmlApplicationContext.getBean(A.class).getName());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

运行的结果如下:

Spring源码系列(三)BeanDefinition(二)

可以看到我们Spring的配置的xml中的BeanDefinitionGenericBeanDefinition那么注解中配置的BeanDefinition又是什么BeanDefinition呢?要回答这个问题我们需要回到原来的继承的类图。三个直接继承AbstractBeanDefinition的类的BeanDefinition已经介绍完了。那么注解中配置BeanDefinition肯定是其他的几个BeanDefinition了。那么具体又是怎么样的呢?下面就让笔者来回答这个问题。

3.3AnnotatedGenericBeanDefinition、ScannedGenericBeanDefinition、ConfigurationClassBeanDefinition

要搞清楚这两个BeanDefinition对应的描述的Bean,我们需要基于注解的方式配置Bean,然后打印出来对应的BeanDefinition。具体的代码如下:

package com.ys.beanDefinition.anno;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.ys.beanDefinition.anno")
public class AppConfig {

    @Bean
    public A a(){
        return new A();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
package com.ys.beanDefinition.anno;

import org.springframework.stereotype.Component;

@Component
public class B {
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
package com.ys.beanDefinition.anno;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        System.out.println("AppConfig:BeanDefinition:" + applicationContext.getBeanFactory().getBeanDefinition("appConfig").getClass().getSimpleName());
        System.out.println("A:BeanDefinition:" + applicationContext.getBeanFactory().getBeanDefinition("a").getClass().getSimpleName());
        System.out.println("B:BeanDefinition:" + applicationContext.getBeanFactory().getBeanDefinition("b").getClass().getSimpleName());
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

运行的结果如下:

Spring源码系列(三)BeanDefinition(二)

可以发现我们加了@Configuration注解的被解析成AnnotatedGenericBeanDefinition,然后在加了@Bean的注解被解析成ConfigurationClassBeanDefinition,然后就是注解扫描来的Bean被解析成ScannedGenericBeanDefinition。所以到此SpringBeanDefinition都有对应的类进行描述了。

可以看到这个三个类都是实现了AnnotatedBeanDefinition接口,那么这个接口中对应的代码如下:

package org.springframework.beans.factory.annotation;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.lang.Nullable;

public interface AnnotatedBeanDefinition extends BeanDefinition {

    //注解的元数据
	AnnotationMetadata getMetadata();

    //工厂方法的元数据
	@Nullable
	MethodMetadata getFactoryMethodMetadata();

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

可以看到上面的接口主要是要实现两个方法,一个是获取对应的注解的元数据,还有一个就是工厂方法的元数据。至于这些细节后面的博客会继续说。

4.写在最后

至此BeanDefinition的介绍就告一段落了。本文主要从介绍上节博客遗留的问题,同时也介绍了一些BeanDefinition的一些常用的实现类。

上一篇:spring学习记录(二)


下一篇:简易版的 Spring 之如何实现 Setter 注入