温馨提示:如果您是刚接触spring源码不久,建议您先阅读BeanDefinitino的前两篇博文才能更好的理解本篇博文
书接上回。
上回咱们讲了BeanDefinition的父接口及父接口实现类。本篇博文咱么继续讲BeanDefinition的实现类。包括AbstractBeanDefinition、RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition、AnnotateGenericBeanDefinition、ScannerGenericBeanDefinition。
1. AbstractBeanDefinition
AbstractBeanDefinition是抽象类,它是众多子类的父类。前两篇文章讲的BeanDefinition属性值大都保存在AbstractBeanDefinition,并实现了子BeanDefinition通用方法。同时它也继承了BeanMetadataAttributeAccessor完成attribute和source的操作。我们看一下它的关键源码:
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
// 此处省略静态变量以及final变量
@Nullable
private volatile Object beanClass;
/**
* bean的作用范围,对应bean属性scope
*/
@Nullable
private String scope = SCOPE_DEFAULT;
/**
* 是否是抽象,对应bean属性abstract
*/
private boolean abstractFlag = false;
/**
* 是否延迟加载,对应bean属性lazy-init
*/
private boolean lazyInit = false;
/**
* 自动注入模式,对应bean属性autowire
*/
private int autowireMode = AUTOWIRE_NO;
/**
* 依赖检查,Spring 3.0后弃用这个属性
*/
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
/**
* 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-on
*/
@Nullable
private String[] dependsOn;
/**
* autowire-candidate属性设置为false,这样容器在查找自动装配对象时,
* 将不考虑该bean,即它不会被考虑作为其他bean自动装配的候选者,
* 但是该bean本身还是可以使用自动装配来注入其他bean的
*/
private boolean autowireCandidate = true;
/**
* 自动装配时出现多个bean候选者时,将作为首选者,对应bean属性primary
*/
private boolean primary = false;
/**
* 用于记录Qualifier,对应子元素qualifier
*/
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);
@Nullable
private Supplier<?> instanceSupplier;
/**
* 允许访问非公开的构造器和方法,程序设置
*/
private boolean nonPublicAccessAllowed = true;
/**
* 是否以一种宽松的模式解析构造函数,默认为true,
* 如果为false,则在以下情况
* interface ITest{}
* class ITestImpl implements ITest{};
* class Main {
* Main(ITest i) {}
* Main(ITestImpl i) {}
* }
* 抛出异常,因为Spring无法准确定位哪个构造函数程序设置
*/
private boolean lenientConstructorResolution = true;
/**
* 对应bean属性factory-bean,用法:
* <bean id = "instanceFactoryBean" class = "example.chapter3.InstanceFactoryBean" />
* <bean id = "currentTime" factory-bean = "instanceFactoryBean" factory-method = "createTime" />
*/
@Nullable
private String factoryBeanName;
/**
* 对应bean属性factory-method
*/
@Nullable
private String factoryMethodName;
/**
* 记录构造函数注入属性,对应bean属性constructor-arg
*/
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
/**
* 普通属性集合,就是存放你业务类的属性的地方
*/
@Nullable
private MutablePropertyValues propertyValues;
/**
* 方法重写的持有者,记录lookup-method、replaced-method元素
*/
@Nullable
private MethodOverrides methodOverrides;
/**
* 初始化方法,对应bean属性init-method
*/
@Nullable
private String initMethodName;
/**
* 销毁方法,对应bean属性destroy-method
*/
@Nullable
private String destroyMethodName;
/**
* 是否执行init-method,程序设置
*/
private boolean enforceInitMethod = true;
/**
* 是否执行destroy-method,程序设置
*/
private boolean enforceDestroyMethod = true;
/**
* 是否是用户定义的而不是应用程序本身定义的,创建AOP时候为true,程序设置
*/
private boolean synthetic = false;
/**
* 定义这个bean的应用,APPLICATION:用户,INFRASTRUCTURE:完全内部使用,与用户无关,
* SUPPORT:某些复杂配置的一部分
* 程序设置
*/
private int role = BeanDefinition.ROLE_APPLICATION;
/**
* bean的描述信息
*/
@Nullable
private String description;
/**
* 这个bean定义的资源
*/
@Nullable
private Resource resource;
}
操作方法我就不列出来了,主要就是对属性的设置和获取,类似于getter和setter方法,读者自行阅读。总之,AbstractBeanDefinition 就是保存了属性值并对属性值进行设置和读取。记住这一点就行了。
当然,有的读者说,源码很简单,但是里面的属性值具体代表啥意思呢?在什么时候用到呢?前两篇博文我说了,我讲解BeanDefinition这块内容就是让大家纯粹的理解BeanDefition的作用,BeanDefition是整个spring源码中的基础。在以后的学习中,BeanDefinition中的属性值作用会慢慢的浮出水面,大家不要着急。
AbstractBeanDefinition 其实已经涵盖了所有属性了,spring为什么要提供这么多的子类?正所谓,既生瑜何生亮!笔者认为,完全可以用一个AbstractBeanDefinition 代替所有的子类,只不过spring为了模块化,不同的BeanDefinition可能从代码角度来讲都一样,但是从设计角度来讲我们要模块化,要拆分,不通模块的BeanDefinition无论从设计还是功能肯定有差异,我们当然可以将这些差异规避在AbstractBeanDefinition ,但是这不利于维护和扩展,更不利于阅读理解。
我们看一下ChildBeanDefinition源码中的类注解:
* <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.
百度翻一下:
意思就是说,spring2.5以后GenericBeanDefinition是首选的,也就是说spring2.5以前的版本根本就没有GenericBeanDefinition这个类。spring总得向前发展啊,更重要的是尽可能的保持向下兼容呀!其实,RootBeanDefinition也有这种类似的注解,你不信你去看源码!现如今,我们已经不使用ChildBeanDefinition了,完全北GenericBeanDefinition给替代了,但是还在使用RootBeanDefinition。
Root,Child根据字面意思,好像是父子关系,AbstractBeanDefinition 中有个属性叫abstract(是否是抽象类),抽象类无法实例化呀,不能保存到beanDefinitionMap容器中啊!有存在的意义吗?
有,模板!如果一个BeanDefinition中的属性abstract为true,它是让spring来继承它,而不是实例化它。
举个例子吧:
//业务类
public class InterService {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
//模板BeanDefinition
RootBeanDefinition root = new RootBeanDefinition();
//设置为抽象类
root.setAbstract(true);
root.setDescription("我是一个模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源码之路");
//注册,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child继承root
ChildBeanDefinition child = new ChildBeanDefinition("interService");
//注册,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((InterService)context.getBean("child")).getName());
}
}
打印结果:
这里讲一下这行代码:
root.getPropertyValues().add("name","源码之路");
上文AbstractBeanDefinition 源码中有一个MutablePropertyValues类型的属性叫propertyValues,我在注释中是这么写的:
/**
* 普通属性集合,就是存放你业务类的属性的地方
*/
@Nullable
private MutablePropertyValues propertyValues;
什么意思呢?propertyValues只能保存你业务类的属性,比如业务类InterService中有个name属性, root.getPropertyValues().add("name","源码之路");
在后期spring实例化过程中,会将propertyValues中的属性值一一对应的赋值给业务对象。等同于xml文件中的配置:
<bean id="index" class="com.InterService" >
<property name="name" value="源码之路"></property>
</bean>
如果,我设置了一个业务类中不存在的属性,就会报错,比如:
我说过,AbstractBeanDefinition中的属性以后都会讲到,别急,这个propertyValues只到啥意思了吧?
继续,再添加一个业务类:
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
//模板BeanDefinition
RootBeanDefinition root = new RootBeanDefinition();
//设置为抽象类
root.setAbstract(true);
root.setDescription("我是一个模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源码之路");
//注册,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child继承root
ChildBeanDefinition child = new ChildBeanDefinition("interService");
child.setBeanClass(User.class);
//注册,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((User)context.getBean("child")).getName());
}
}
我们只是增加了child.setBeanClass(User.class);这行代码
打印结果:
也就是说User类相当于继承了InterService类,等同于xml文件:
<bean id="index" class="com.InterService" >
<property name="name" value="源码之路"></property>
</bean>
<bean id="user" class="com.User" parent="index">
</bean>
这里很绕,笔者当时为了弄懂这里也是费了好大的劲。多读两遍就理解了。
2. GenericBeanDefinition
上文我们说GenericBeanDefinition可以替代RootBeanDefinition和ChildBeanDefinition,我们测试一下:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
//模板BeanDefinition
GenericBeanDefinition root = new GenericBeanDefinition();
//设置为抽象类
root.setAbstract(true);
root.setDescription("我是一个模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源码之路");
root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
//注册,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child继承root
GenericBeanDefinition child = new GenericBeanDefinition();
child.setParentName("interService");
child.setAbstract(false);
child.setBeanClass(User.class);
//注册,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((User)context.getBean("child")).getName());
System.out.println(context.getBeanDefinition("child").getScope());
}
}
打印结果:
我们阅读下GenericBeanDefinition源码:
public class GenericBeanDefinition extends AbstractBeanDefinition {
//父BeanDefinition名字
@Nullable
private String parentName;
/**
* Create a new GenericBeanDefinition, to be configured through its bean
* properties and configuration methods.
* @see #setBeanClass
* @see #setScope
* @see #setConstructorArgumentValues
* @see #setPropertyValues
* 构造方法,所有属性均为空
*/
public GenericBeanDefinition() {
super();
}
/**
* Create a new GenericBeanDefinition as deep copy of the given
* bean definition.
* @param original the original bean definition to copy from
* 从一个给定的BeanDefinition中将属性值copy给新的GenericBeanDefinition
*/
public GenericBeanDefinition(BeanDefinition original) {
super(original);
}
//设置父类名称
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
//获取父类名称
@Override
@Nullable
public String getParentName() {
return this.parentName;
}
//根据当前GenericBeanDefinition克隆一个新的GenericBeanDefinition
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
return new GenericBeanDefinition(this);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof GenericBeanDefinition)) {
return false;
}
GenericBeanDefinition that = (GenericBeanDefinition) other;
return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Generic bean");
if (this.parentName != null) {
sb.append(" with parent '").append(this.parentName).append("'");
}
sb.append(": ").append(super.toString());
return sb.toString();
}
}
3. RootBeanDefinition
但是,RootBeanDefinition却不可以替换ChildBeanDefinition
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
//模板BeanDefinition
RootBeanDefinition root = new RootBeanDefinition();
//设置为抽象类
root.setAbstract(true);
root.setDescription("我是一个模板");
root.setBeanClass(InterService.class);
root.getPropertyValues().add("name","源码之路");
root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
//注册,放到IOC容器中
context.registerBeanDefinition("interService",root);
//child继承root
RootBeanDefinition child = new RootBeanDefinition();
child.setParentName("interService");
child.setBeanClass(User.class);
//注册,放到IOC容器中
context.registerBeanDefinition("child",child);
context.refresh();
System.out.println(((User)context.getBean("child")).getName());
System.out.println(context.getBeanDefinition("child").getScope());
}
}
为什么?我们看child.setParentName("interService")这行代码的源码:
@Override
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}
看到了吧,你设置父类的时候spring给你抛异常,不允许。RootBeanDefinition的所有构造函数也不给你提供一个设置父类的参数。那么问题来了,spring为什么这么做?笔者构建好了spring源码,然后笔者把RootBeanDefinition的源码改了:
首先,在RootBeanDefinition增加一个parentName的属性
@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
.....
//父类名称
private String parentName;
....
{
其次,修改setParentName
@Override
public void setParentName(@Nullable String parentName) {
// if (parentName != null) {
// throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
// }
this.parentName = parentName;
}
最后修改getParentName方法,注意,spring原来的就是return null;
@Override
public String getParentName() {
// return null;
return this.parentName;
}
打印结果:
此时,RootBeanDefinition充当了ChildBeanDefinition的角色。留作业,spring为什么这么做?不要告诉我setParentName抛异常所以不允许,我已经证明该源码可以了,我问的是spring源码作者他当时咋想的?我给你打个样:这里涉及到bean合并。
最后读下RootBeanDefinition的源码吧:
public class RootBeanDefinition extends AbstractBeanDefinition {
//BeanDefinitionHolder存储有Bean的名称、别名、BeanDefinition
@Nullable
private BeanDefinitionHolder decoratedDefinition;
// AnnotatedElement 是java反射包的接口,通过它可以查看Bean的注解信息
@Nullable
private AnnotatedElement qualifiedElement;
//允许缓存
boolean allowCaching = true;
//从字面上理解:工厂方法是否唯一
boolean isFactoryMethodUnique = false;
//封装了java.lang.reflect.Type,提供了泛型相关的操作,具体请查看:
// ResolvableType 可以专题去了解一下子,虽然比较简单 但常见
@Nullable
volatile ResolvableType targetType;
//缓存class,表明RootBeanDefinition存储哪个类的信息
@Nullable
volatile Class<?> resolvedTargetType;
//缓存工厂方法的返回类型
@Nullable
volatile ResolvableType factoryMethodReturnType;
/** Common lock for the four constructor fields below */
final Object constructorArgumentLock = new Object();
//缓存已经解析的构造函数或是工厂方法,Executable是Method、Constructor类型的父类
@Nullable
Executable resolvedConstructorOrFactoryMethod;
//表明构造函数参数是否解析完毕
boolean constructorArgumentsResolved = false;
//缓存完全解析的构造函数参数
@Nullable
Object[] resolvedConstructorArguments;
//缓存待解析的构造函数参数,即还没有找到对应的实例,可以理解为还没有注入依赖的形参
@Nullable
Object[] preparedConstructorArguments;
/** Common lock for the two post-processing fields below */
final Object postProcessingLock = new Object();
//表明是否被MergedBeanDefinitionPostProcessor处理过
boolean postProcessed = false;
//在生成代理的时候会使用,表明是否已经生成代理
@Nullable
volatile Boolean beforeInstantiationResolved;
//实际缓存的类型是Constructor、Field、Method类型
@Nullable
private Set<Member> externallyManagedConfigMembers;
//InitializingBean中的init回调函数名——afterPropertiesSet会在这里记录,以便进行生命周期回调
@Nullable
private Set<String> externallyManagedInitMethods;
//DisposableBean的destroy回调函数名——destroy会在这里记录,以便进行生命周期回调
@Nullable
private Set<String> externallyManagedDestroyMethods;
//===========方法(只例举部分)
// 由此看出,RootBeanDefiniiton是木有父的
@Override
public String getParentName() {
return null;
}
@Override
public void setParentName(@Nullable String parentName) {
if (parentName != null) {
throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
}
}
// 拿到class类型
@Nullable
public Class<?> getTargetType() {
if (this.resolvedTargetType != null) {
return this.resolvedTargetType;
}
ResolvableType targetType = this.targetType;
return (targetType != null ? targetType.resolve() : null);
}
@Override
public RootBeanDefinition cloneBeanDefinition() {
return new RootBeanDefinition(this);
}
}
可以看到许多与反射相关的对象,这说明spring底层采用的是反射机制。
总结一下,RootBeanDefiniiton保存了以下信息:
1. 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
2. Bean的注解(AnnotatedElement)
3. 具体的工厂方法(Class类型),包括工厂方法的返回类型,工厂方法的Method对象
4. 构造函数、构造函数形参类型
5. Bean的class对象
可以看到,RootBeanDefinition与AbstractBeanDefinition是互补关系,RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本完善
4. ChildBeanDefinition
ChildBeanDefinition不能独立存在,他必须继承一个父类,为什么?我们看源码:
public class ChildBeanDefinition extends AbstractBeanDefinition {
//父类名称
@Nullable
private String parentName;
/**
* Create a new ChildBeanDefinition for the given parent, to be
* configured through its bean properties and configuration methods.
* @param parentName the name of the parent bean
* @see #setBeanClass
* @see #setScope
* @see #setConstructorArgumentValues
* @see #setPropertyValues
* 构造函数,必须设置一个父类
*/
public ChildBeanDefinition(String parentName) {
super();
this.parentName = parentName;
}
/**
* Create a new ChildBeanDefinition for the given parent.
* @param parentName the name of the parent bean
* @param pvs the additional property values of the child
* 构造函数,设置父类和业务类属性
*/
public ChildBeanDefinition(String parentName, MutablePropertyValues pvs) {
super(null, pvs);
this.parentName = parentName;
}
/**
* Create a new ChildBeanDefinition for the given parent.
* @param parentName the name of the parent bean
* @param cargs the constructor argument values to apply
* @param pvs the additional property values of the child
* 构造函数,设置父类,业务类构造函数的参数,业务类属性
*/
public ChildBeanDefinition(
String parentName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
}
/**
* Create a new ChildBeanDefinition for the given parent,
* providing constructor arguments and property values.
* @param parentName the name of the parent bean
* @param beanClass the class of the bean to instantiate
* @param cargs the constructor argument values to apply
* @param pvs the property values to apply
* 构造函数,设置父类,业务类beanClass,业务类构造函数的参数,业务类属性
*/
public ChildBeanDefinition(
String parentName, Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
setBeanClass(beanClass);
}
/**
* Create a new ChildBeanDefinition for the given parent,
* providing constructor arguments and property values.
* Takes a bean class name to avoid eager loading of the bean class.
* @param parentName the name of the parent bean
* @param beanClassName the name of the class to instantiate
* @param cargs the constructor argument values to apply
* @param pvs the property values to apply
* 构造函数,设置父类,业务类名称,业务类构造函数的参数,业务类属性
*/
public ChildBeanDefinition(
String parentName, String beanClassName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
super(cargs, pvs);
this.parentName = parentName;
setBeanClassName(beanClassName);
}
/**
* Create a new ChildBeanDefinition as deep copy of the given
* bean definition.
* @param original the original bean definition to copy from
* 构造函数,从另一个ChildBeanDefinition进行属性copy
*/
public ChildBeanDefinition(ChildBeanDefinition original) {
super(original);
}
//设置父类名称
@Override
public void setParentName(@Nullable String parentName) {
this.parentName = parentName;
}
//获取父类名称
@Override
@Nullable
public String getParentName() {
return this.parentName;
}
//校验,会发现,如果没有父类就会报错
@Override
public void validate() throws BeanDefinitionValidationException {
super.validate();
if (this.parentName == null) {
throw new BeanDefinitionValidationException("'parentName' must be set in ChildBeanDefinition");
}
}
//生成一个新的ChildBeanDefinition,并进行属性值复制
@Override
public AbstractBeanDefinition cloneBeanDefinition() {
return new ChildBeanDefinition(this);
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof ChildBeanDefinition)) {
return false;
}
ChildBeanDefinition that = (ChildBeanDefinition) other;
return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other));
}
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.parentName) * 29 + super.hashCode();
}
@Override
public String toString() {
return "Child bean with parent '" + this.parentName + "': " + super.toString();
}
}
ChildBeanDefinition所有的构造方法都要求设置父类名称,所以从代码角度讲,它必须依赖于父类存在,不能单独存在。spring官方当初设置ChildBeanDefinition的初衷就是永远让它作为一个子bd存在。但是它现在完全可以被GenericBeanDefinition替代了。
我们来做个总结吧:
- RootBeanDefinition作为父bd出现,不能作为子bd出现。
- ChildBeanDefinition必须作为子bd出现。
- GenericBeanDefinition可以作为父bd出现,也可以作为子bd出现。他可以完全替代ChildBeanDefinition,但不能完全替代RootBeanDefinition,这一点在以后的bean合并博文中会讲解,尽请期待。
5. AnnotatedBeanDefinition
现如今,大家都用spring注解扫描的方式进行开发,首先在业务类上添加一个注解,比如@Service、@Controller、@Component等,spring扫描所有类并判断是否加入相关注解,有注解的类会生成一个BeanDefinition并添加到IOC容器中。我们称注解BeanDefinition。
AnnotatedBeanDefinition是一个注解bd的接口,可以获取BeanDefinition注解相关数据。它有两个实现类ConfigurationClassBeanDefinition、ScannedGenericBeanDefinition和AnnotatedGenericBeanDefinition。
AnnotatedBeanDefinition接口源码很容易理解:
public interface AnnotatedBeanDefinition extends BeanDefinition {
/**
* Obtain the annotation metadata (as well as basic class metadata)
* for this bean definition's bean class.
* @return the annotation metadata object (never {@code null})
* 获取注解信息
*/
AnnotationMetadata getMetadata();
/**
* Obtain metadata for this bean definition's factory method, if any.
* @return the factory method metadata, or {@code null} if none
* @since 4.1.1
* 获取此beanDefinition的工厂方法的元数据(如果有)。
*/
@Nullable
MethodMetadata getFactoryMethodMetadata();
}
这两个方法是在子类中实现的,我们先查看这两个方法返回的具体信息:
//业务类
@Component
@Description("业务类")
@Scope("singleton")
public class InterService {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
//测试类
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
context.refresh();
ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) context.getBeanDefinition("interService");
//查看spring给我生成的具体BeanDefinition类型
System.out.println(beanDefinition.getClass().getSimpleName());
//获取注解信息
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
//获取工厂方法元数据
MethodMetadata methodMetadata = beanDefinition.getFactoryMethodMetadata();
System.out.println();
}
}
测试结果:
你就理解为存储了业务类的注解信息,便于spring后续的解析。
6. ScannedGenericBeanDefinition
有@Component注解的类,会生成ScannedGenericBeanDefinition类型的Bean定义。注意其它继承了@Component的注解如@Service、@Controller、@Repository也是生成ScannedGenericBeanDefinition类型的Bean定义。
ScannedGenericBeanDefinition实现了AnnotatedBeanDefinition接口且继承了GenericBeanDefinition类,scan翻译成中文就是扫描的意思,顾名思义,它就是spring扫描后生成的BeanDefinition。它的源码也很容易理解,读者自行查阅。
7.AnnotatedGenericBeanDefinition
AnnotatedGenericBeanDefinition在两种地方会使用。spring启动时会生成一个AnnotatedBeanDefinitionReader读取器:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
context.refresh();
System.out.println(context.getBeanDefinition("interService").getClass().getSimpleName());
System.out.println();
}
}
public AnnotationConfigApplicationContext() {
//在IOC容器中初始化一个 注解bean读取器AnnotatedBeanDefinitionReader
this.reader = new AnnotatedBeanDefinitionReader(this);
//在IOC容器中初始化一个 按类路径扫描注解bean的 扫描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
- 解析配置类
主要看这行代码:
context.register(Config.class);
查看以下源码:context.register(Config.class)
->this.reader.register(componentClasses);
->registerBean(componentClass);
->doRegisterBean(beanClass, null, null, null);
->doRegisterBean
,最后跟到doRegisterBean方法:
//第一行代码
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
.......中间省略........
//最后一行代码,注册到IOC容器
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
看到了码,spring将你的配置定生成了一个AnnotatedGenericBeanDefinition。
我们来测试一下:
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
context.refresh();
System.out.println(context.getBeanDefinition("config").getClass().getSimpleName());
System.out.println();
}
}
打印结果:
AnnotatedGenericBeanDefinition
- 手动注册
其实就跟上面配置类一样。我们不让spring自动扫描,我们手动注册一个业务类。
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
context.refresh();
//手动注册一个业务类
context.register(InterService.class);
System.out.println(context.getBeanDefinition("interService").getClass().getSimpleName());
System.out.println();
}
}
打印结果:
AnnotatedGenericBeanDefinition
总结:通过AnnotatedBeanDefinitionReader手动注册的类sping都会生成AnnotatedGenericBeanDefinition。而自动扫描的都会生成ScannedGenericBeanDefinition。
8.ConfigurationClassBeanDefinition
首先需要注意的是,ConfigurationClassBeanDefinition是一个内部类,其外部类是ConfigurationClassBeanDefinitionReader,这个类负责将@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition类,源码就不过多解释了,和之前几个BeanDefinition差不多。
默认设置
如果@Bean注解没有指定bean的名字,默认会用方法的名字命名bean。
@Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会成为工厂方法,通过工厂方法实例化Bean,而不是直接通过构造函数初始化。
@Bean注解注释的类会使用构造函数自动装配。
//在@Configuration注解的类中,使用@Bean注解实例化的Bean,其定义会用ConfigurationClassBeanDefinition存储。
@Configuration
public class ConfigurationTest {
@Bean
public User getUser(){
return new User();
}
}
public class User {
private String name;
}
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
//注册配置类
context.register(Config.class);
context.refresh();
System.out.println(context.getBeanDefinition("getUser").getClass().getSimpleName());
}
}
至此,BeanDefinition整个家族继承关系讲完了,相信认真读过这三篇博文的读者对BeanDefinition都有深入的理解了,建议读者结合这三篇博文认真练习,BeanDefinition打好基础了后续spring源码的阅读才会游刃有余,否则很难读下去。
笔者相信,BeanDefinition中的很多属性大家都不是很理解在spring中到底起了什么作用,这个没关系,在后续源码学习过程中这些属性的作用会慢慢浮出水面,到时候再回过头复习才会恍然大糊涂。