1.写在前面
在上篇博客《Spring源码系列(二)BeanDefinition(一)》我们大概的介绍了下BeanDefinition
接口中的一些属性,还有两个BeanDefinition
的父接口。同时简单的介绍了下对应的实现类AbstractBeanDefinition
。但是还有些属性没有介绍,这篇博客会把这些属性介绍了,同时会介绍一下BeanDefinition
接口的一些实现类。还是那句话,Spring
创建Bean
都是根据这个BeanDefinition
来的,所以要搞懂Spring
的源码,必须要搞懂这些常用的BeanDefinition
的实现类
2.BeanDefinition的一些常用属性
这节主要讲下上节博客中,没有介绍完的BeanDefinition
的属性。例如ConstructorArgumentValues
、MutablePropertyValues
、parentName
等属性。我们再来看下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
运行的结果如下:
可以看的对应的参数已经填充进去了。但是这两个参数返回的类型是ConstructorArgumentValues
和MutablePropertyValues
。这个两个类型我们有必要看下,具体的代码如下:
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
的常用的一些实现类。具体的结构图如下:
上篇博客中我们已经介绍了AbstractBeanDefinition
,它主要是对BeanDefinition
一些简单的实现,和对BeanDefinition
的两个接口进行了相应的实现,但是这个类是个抽象,无法实例化。同时对一些相同的属性和方法进行了抽象,其他的实现类主要实现最主要的部分就行了。通过上图我们可以看到直接继承AbstractBeanDefinition
的类有三个,分别是RootBeanDefinition
、ChildBeanDefinition
、GenericBeanDefinition
我们先来介绍这个几个BeanDefinition
3.1RootBeanDefinition
与ChildBeanDefinition
打开对应的RootBeanDefinition
和ChildBeanDefinition
代码,注释中有一句话,我们可以看看,具体的内容如下:
这句话的意思就是:从Spring 2.5开始,以编程方式注册Bean定义的首选方式是GenericBeanDefinition
类,该类允许通过GenericBeanDefinition
的setParentName
方法动态定义父依赖项。对于大多数用例,这有效地代替了RootBeanDefinition
和ChildBeanDefinition
类。也就是这个两个类是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
还是原来的代码,我们只不过将其中一行的代码注释掉了。然后运行的结果如下:
会报创建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
运行的结果如下:
可以发现我们的容器在创建的时候已经不报错了。我们已经完成了对应模板BeanDefinition
的创建了。但是要怎么让其他的BeanDefinition
继承这个模板BeanDefinition
呢?从而获得相同的属性呢?这个时候就需要用到ChildBeanDefinition
这个类。现在假设有以下的应用场景,所有的Bean
的都是支持懒加载的。我们总不能给每一个BeanDefinition
设置成懒加载为true
吧!这个时候就需要用到我们的RootBeanDefinition
和ChildBeanDefinition
组合场景了。具体的代码如下:
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
中所创建的两个Bean
的name
的值应该都是king
,具体的运行结果如下:
具体的结果正如我们猜测的那样,A和B中name的属性的值都为king。那么这儿merge(合并)的逻辑又是什么呢?后面的博客会讲。可能这个时候可能有读者会问既然有了这些,为什么还要有GenericBeanDefinition
呢?这个时候就不得不说下RootBeanDefinition
与ChildBeanDefinition
的缺点了。
其中RootBeanDefinition
不能作为子BeanDefinition
,具体的可以看下Spring
的源码,具体的代码如下:
我们可以看到Spring
的源码直接将setParentName
方法直接抛出了异常,所以RootBeanDefinition
不能作为子的BeanDefinition
,那可能有读者会问:为什么不能设置为子BeanDefinition
?后面的博客会讲的。
同时ChildBeanDefinition
为什么只能作为子BeanDefinition
呢?我们直接看源码即可,具体的代码如下:
我们可以看到所有的构造函数有都是要提供一个parentName
的属性,所以它只能作为子BeanDefinition
。所以在Spring2.5以后就出现了GenericBeanDefinition
,就是为了解决这些问题。
3.2GenericBeanDefinition
字面上的意思就是通用的BeanDefinition
。同时也是为了解决RootBeanDefinition
和ChildBeanDefinition
上面提到的问题而出现的。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
运行的结果如下:
可以看到我们的运行的结果和前面的一样,同时这个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
的配置的xml
中的BeanDefinition
是GenericBeanDefinition
那么注解中配置的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
运行的结果如下:
可以发现我们加了@Configuration
注解的被解析成AnnotatedGenericBeanDefinition
,然后在加了@Bean
的注解被解析成ConfigurationClassBeanDefinition
,然后就是注解扫描来的Bean被解析成ScannedGenericBeanDefinition
。所以到此Spring
的BeanDefinition
都有对应的类进行描述了。
可以看到这个三个类都是实现了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
的一些常用的实现类。