Spring 的IoC容器中核心定义之------BeanDefinition深入分析
Spring IoC 容器 Management 一个或多个 bean。这些 bean 是使用您提供给容器的配置元数据创建的(例如,以 XML <bean/>
定义的形式)。
在容器本身内,这些 bean 定义表示为BeanDefinition
对象,其中包含(除其他信息外)以下元数据:
- 包限定的类名:通常,定义了 Bean 的实际实现类。
- Bean 行为配置元素,用于声明 Bean 在容器中的行为(作用域,生命周期回调等)。
- 引用其他 bean 进行其工作所需的 bean。这些引用也称为协作者或依赖项。
- 要在新创建的对象中设置的其他配置设置,例如,池的大小限制或在 Management 连接池的 bean 中使用的连接数。
该元数据转换为构成每个 bean 定义的一组属性。下表描述了这些属性:
表 1. bean 定义
Property | Explained in… |
Class | |
Name | |
Scope | |
Constructor arguments | |
Properties | |
Autowiring mode | |
延迟初始化模式 | |
Initialization method | |
Destruction method |
除了包含有关如何创建特定 bean 的信息的 bean 定义之外,ApplicationContext
实现还允许注册在容器外部(由用户)创建的现有对象。这是通过getBeanFactory()
方法访问 ApplicationContext 的 BeanFactory 来完成的,该方法返回 BeanFactory DefaultListableBeanFactory
的实现。 DefaultListableBeanFactory
通过registerSingleton(..)
和registerBeanDefinition(..)
方法支持此注册。但是,典型的应用程序只能与通过常规 bean 定义元数据定义的 bean 一起使用。
BeanDefinition 是容器对于bean配置的内部表示,Spring 将各个 bean 的 BeanDefinition 实例注册记录在 BeanDefinitionRegistry 中,该接口定义了对 BeanDefinition 的各种增删查操作,类似于内存数据库,其实现类 SimpleBeanDefinitionRegistry 主要以 Map 作为存储标的。
下面转载:https://cloud.tencent.com/developer/article/1497805
前言
在前面分析Spring IoC容器的时候,贯穿全文的一个概念:Bean定义信息。它是Spring容器的一个核心概念,那么本文就深入分析一下BeanDefinition
这个接口(类)。
Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。 不管是是通过xml配置文件的\<Bean>
标签,还是通过注解配置的@Bean
,它最终都会被解析成一个Bean定义信息(对象),最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作
从上可知BeanDefinition
这个接口对Spring IoC容器的重要之处,所以了解好了它(以及子类),能让我们更大视野的来看Spring管理Bean的一个过程,也能透过现象看本质。
透彻理解Spring容器是打开Spring Boot大门的一把钥匙
下面用一个非常形象的比喻,来形容Spring IoC容器和BeanDefinition
之前的关系。
比喻:BeanFactory和BeanDefinition
Spring IoC容器比作一间餐馆,当你来到餐馆,通常会直接招呼服务员:点菜!至于菜的原料是什么?如何用原料把菜做出来?可能你根本就不关心。 IoC容器也是一样,你只需要告诉它需要某个bean,它就把对应的实例(instance)扔给你,至于这个bean是否依赖其他组件,怎样完成它的初始化,根本就不需要你关心。
那么问题来了,作为餐馆,想要做出菜肴,得知道菜的原料和菜谱。同样地,IoC容器想要管理各个业务对象以及它们之间的依赖关系,需要通过某种途径来记录和管理这些信息。 BeanDefinition
对象就承担了这个责任
容器中的每一个bean都会有一个对应的BeanDefinition
实例,该实例负责保存bean对象的 所有 必要信息,包括bean对象的class类型、是否是抽象类、构造方法和参数、其它属性等等(所以BeanDefinition
就好比做菜的原料)
需要说明的一点是:加入你是自己直接通过
SingletonBeanRegistry#registerSingleton
向容器手动注入Bean的,那么就不会存在这份Bean定义信息的,这点需要注意。 Spring内部有不少这样的例子(因为这种Bean非常简单,根本不需要定义信息):beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME, Collections.unmodifiableMap(attributeMap));
现在可以开始做菜了吗?其实还不行,因为还没有菜谱(不知道做什么菜,怎么做~) BeanDefinitionRegistry
和 BeanFactory
就是这份菜谱,BeanDefinitionRegistry
抽象出bean的注册逻辑,而BeanFactory
则抽象出了bean的管理逻辑 各个BeanFactory的实现类就具体承担了bean的注册以及管理工作
DefaultListableBeanFactory
作为一个比较通用的BeanFactory
实现,它同时也实现了BeanDefinitionRegistry
接口,因此它就承担了Bean的注册管理工作
最后我们总结一下比喻关系:
- Spring IoC容器:餐馆(服务员)
-
BeanDefinitionRegistry和 BeanFactory
:菜谱 -
BeanDefinitionRegistry
:抽象出来的,向菜谱里注册菜(的管理器) -
BeanFactory
:抽象出来的,管理这些菜谱(的管理器) -
BeanDefinition
:原料(做菜所需要的原料) -
DefaultListableBeanFactory
:具体实施者(具体注册菜谱、做菜的实施者) - 依赖注入的使用者:客户(进店吃饭的人)
BeanDefinition
源码分析
总体的 Java Class Diagrams 图:
因为它继承了AttributeAccessor,和BeanMetadataElement
,所以我们先有必要来了解下这两个接口:
AttributeAccessor
:定义了对对象元数据访问的抽象接口
// 接口都比较简单 就是定义了对对象属性的一些访问方法
//说明它可以持有Bean元数据元素,作用是可以持有XML文件的一个bean标签对应的Object(或者@Configuration元配置对象)
public interface AttributeAccessor {
void setAttribute(String name, @Nullable Object value);
@Nullable
Object getAttribute(String name);
@Nullable
Object removeAttribute(String name);
boolean hasAttribute(String name);
String[] attributeNames();
}
AttributeAccessorSupport
是唯一抽象实现,内部基于LinkedHashMap
实现了所有的接口,供其他子类继承使用 主要针对属性CRUD操作
BeanMetadataElement
:具有访问source(配置源)的能力
这个方法在@Configuration
中使用较多,因为它会被代理
//接口提供了一个getResource()方法,用来传输一个可配置的源对象。
public interface BeanMetadataElement {
/**
* Return the configuration source {@code Object} for this metadata element
* (may be {@code null}).
* 返回元数据元素配置元对象
*/
@Nullable
Object getSource();
}
BeanDefinition
:定义了Bean的各种信息
一个BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息。
BeanDefinition
仅仅是一个最简单的接口,主要功能是允许BeanFactoryPostProcessor
例如PropertyPlaceHolderConfigure
能够检索并修改属性值和别的bean的元数据
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
// 单例Bean还是原型Bean
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// Bean角色
int ROLE_APPLICATION = 0; //应用程序重要组成部分
int ROLE_SUPPORT = 1; //做为大量配置的一部分(支持、扩展类) 实际上就是说,我这个Bean是用户的,是从配置文件中过来的。
int ROLE_INFRASTRUCTURE = 2; //指内部工作的基础构造 实际上是说我这Bean是Spring自己的,和你用户没有一毛钱关系
// Modifiable attributes
//parent definition(若存在父类的话,就设置进去)
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
// 指定Class类型。需要注意的是该类型还有可能被改变在Bean post-processing阶段
// 若是getFactoryBeanName getFactoryMethodName这种情况下会改变
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
//SCOPE_SINGLETON或者SCOPE_PROTOTYPE两种
void setScope(@Nullable String scope);
@Nullable
String getScope();
// @Lazy 是否需要懒加载(默认都是立马加载的)
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 此Bean定义需要依赖的Bean(显然可以有多个)
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
// 这个Bean是否允许被自动注入到别的地方去(默认都是被允许的)
// 注意:此标志只影响按类型装配,不影响byName的注入方式的~~~~
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 是否是首选的 @Primary
void setPrimary(boolean primary);
boolean isPrimary();
// 指定使用的工厂Bean(若存在)的名称~
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
//指定工厂方法~
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
// 获取此Bean的构造函数参数值们 ConstructorArgumentValues:持有构造函数们的
// 绝大多数情况下是空对象 new ConstructorArgumentValues出来的一个对象
// 当我们Scan实例化Bean的时候,可能用到它的非空构造,这里就会有对应的值了,然后后面就会再依赖注入了
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
// 获取普通属性集合~~~~
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// Read-only attributes
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
// 对应上面的role的值
int getRole();
//@Description
@Nullable
String getDescription();
// 返回该Bean定义来自于的资源的描述(用于在出现错误时显示上下文)
@Nullable
String getResourceDescription();
//返回原始BeanDefinition,如果没有则返回@null
// 若这个Bean定义被代理、修饰过 这个方法可以返回原始的
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
抽象实现、实现类们。上面已经画出了一些类的结构图,下面一个个来看
子接口:AnnotatedBeanDefinition
public interface AnnotatedBeanDefinition extends BeanDefinition {
//获取该bean definition的注解元数据
AnnotationMetadata getMetadata();
//@since 4.1.1
//Obtain metadata for this bean definition's factory method(如果不存在就返回null)
@Nullable
MethodMetadata getFactoryMethodMetadata();
}
AnnotationMetadata
定义了访问特定类的注解的抽象接口,它不需要加载该类即可访问
该注解Bean定义旗下三大实现类:ScannedGenericBeanDefinition
、ConfigurationClassBeanDefinition
、AnnotatedGenericBeanDefinition
抽象实现:AbstractBeanDefinition
AbstractBeanDefinition
实现了BeanDefinition
定义的一系列操作,定义了描述Bean画像的一系列属性,在AbstractBeanDefinition
的基础上,Spring
衍生出了一系列具有特殊用途的BeanDefinition
。
实现代码非常的多:
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
implements BeanDefinition, Cloneable {
//=====================定义众多常量。这一些常量会直接影响到spring实例化Bean时的策略
// 个人觉得这些常量的定义不是必须的,在代码里判断即可。Spring定义这些常量的原因很简单,便于维护,让读代码的人知道每个值的意义(所以以后我们在书写代码时,也可以这么来搞)
//默认的SCOPE,默认是单例
public static final String SCOPE_DEFAULT = "";
// 自动装配的一些常量
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
@Deprecated
public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
//检查依赖是否合法,在本类中,默认不进行依赖检查
public static final int DEPENDENCY_CHECK_NONE = 0; // 不进行检查
public static final int DEPENDENCY_CHECK_OBJECTS = 1; //如果依赖类型为对象引用,则需要检查
public static final int DEPENDENCY_CHECK_SIMPLE = 2; //对简单属性的依赖进行检查
public static final int DEPENDENCY_CHECK_ALL = 3; //对所有属性的依赖进行检查
//若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字,目前来说,推断的销毁方法的名字一般为close或是shutdown
//(即未指定Bean的销毁方法,但是内部定义了名为close或是shutdown的方法,则容器推断其为销毁方法)
public static final String INFER_METHOD = "(inferred)";
//=====================属性:基本囊括了Bean实例化需要的所有信息
//Bean的class对象或是类的全限定名
@Nullable
private volatile Object beanClass;
//默认的scope是单例
@Nullable
private String scope = SCOPE_DEFAULT;
//默认不为抽象类
private boolean abstractFlag = false;
//默认不进行自动装配
private boolean lazyInit = false;
//默认不是懒加载
private int autowireMode = AUTOWIRE_NO;
//默认不进行依赖检查
private int dependencyCheck = DEPENDENCY_CHECK_NONE;
// @@DependsOn 默认没有
@Nullable
private String[] dependsOn;
// autowire-candidate属性设置为false,这样容器在查找自动装配对象时,将不考虑该bean,
// 备注:并不影响本身注入其它的Bean
private boolean autowireCandidate = true;
// 默认不是首选的
private boolean primary = false;
//用于记录Qualifier,对应子元素qualifier=======这个字段有必要解释一下
// 唯一向这个字段放值的方法为本类的:public void addQualifier(AutowireCandidateQualifier qualifier) copyQualifiersFrom这个不算,那属于拷贝
// 调用处:AnnotatedBeanDefinitionReader#doRegisterBean 但是Spring所有调用处,qualifiers字段传的都是null~~~~~~~~~尴尬
// 通过我多放跟踪发现,此处这个字段目前【永远】不会被赋值(除非我们手动调用对应方法为其赋值) 但是有可能我才疏学浅,若有知道的 请告知,非常非常感谢 我考虑到它可能是预留字段~~~~
// 我起初以为这样可以赋值:
//@Qualifier("aaa")
//@Service
//public class HelloServiceImpl 没想到,也是不好使的,Bean定义里面也不会有值
// 因此对应的方法getQualifier和getQualifiers 目前应该基本上都返回null或者[]
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);
//我理解为通过这个函数的逻辑初始化Bean,而不是构造函数或是工厂方法(相当于自己去实例化,而不是交给Bean工厂)
@Nullable
private Supplier<?> instanceSupplier;
//是否允许访问非public方法和属性,应用于构造函数、工厂方法、init、destroy方法的解析 默认是true,表示啥都可以访问
private boolean nonPublicAccessAllowed = true;
// 是否以一种宽松的模式解析构造函数,默认为true(宽松和严格体现在类型匹配上)
private boolean lenientConstructorResolution = true;
//工厂类名(注意是String类型,不是Class类型) 对应bean属性factory-method
@Nullable
private String factoryBeanName;
//工厂方法名(注意是String类型,不是Method类型)
@Nullable
private String factoryMethodName;
//记录构造函数注入属性,对应bean属性constructor-arg
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
//Bean属性的名称以及对应的值,这里不会存放构造函数相关的参数值,只会存放通过setter注入的依赖
@Nullable
private MutablePropertyValues propertyValues;
//方法重写的持有者,记录lookup-method、replaced-method元素 @Lookup等
@Nullable
private MethodOverrides methodOverrides;
//init函数的名字
@Nullable
private String initMethodName;
//destory函数的名字
@Nullable
private String destroyMethodName;
//是否执行init-method,程序设置
private boolean enforceInitMethod = true;
private boolean enforceDestroyMethod = true;
//是否是合成类(是不是应用自定义的,例如生成AOP代理时,会用到某些辅助类,这些辅助类不是应用自定义的,这个就是合成类)
//创建AOP时候为true
private boolean synthetic = false;
//Bean的角色,为用户自定义Bean
private int role = BeanDefinition.ROLE_APPLICATION;
// Bean的描述信息
@Nullable
private String description;
//the resource that this bean definition came from
// 这个Bean哪儿来的
@Nullable
private Resource resource;
//=====================方法:就不逐一解释了,大部分都是get、set 只贴出一些特殊的
// 其实就是给reource赋值了,使用了BeanDefinitionResource
public void setOriginatingBeanDefinition(BeanDefinition originatingBd) {
this.resource = new BeanDefinitionResource(originatingBd);
}
// 上面有赋值,所以get的时候就是返回上面set进来的值
public BeanDefinition getOriginatingBeanDefinition() {
return (this.resource instanceof BeanDefinitionResource ?
((BeanDefinitionResource) this.resource).getBeanDefinition() : null);
}
//克隆Bean的定义信息
@Override
public Object clone() {
return cloneBeanDefinition();
}
public abstract AbstractBeanDefinition cloneBeanDefinition();
}
AbstractBeanDefinition定义了一系列描述Bean画像的属性,通过这个类,可以窥见Bean的某些默认设置(例如默认为单例等)。
从上图可以看出,接下俩需要看具体衍生出来的实现类了,先看RootBeanDefinition
、ChildBeanDefinition
、GenericBeanDefinition
。他们都是AbstractBeanDefinition
的直接实现类
GenericBeanDefinition
:标准bean definition,通用的
除了具有指定类、可选的构造参数值和属性参数这些其它bean definition
一样的特性外,它还具有通过parenetName
属性来灵活(动态)
设置parent bean definition,而非硬编码作为root bean definition
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
// 向工厂里注册Bean信息
GenericBeanDefinition parentBeanDef = new GenericBeanDefinition();
parentBeanDef.setBeanClass(Parent.class);
parentBeanDef.setBeanClassName(Parent.class.getName());
parentBeanDef.setScope(BeanDefinition.SCOPE_SINGLETON);
// 就这样,我们可以动态的给子Bean 设置一个父Bean进去
GenericBeanDefinition childBeanDef = new GenericBeanDefinition();
childBeanDef.setParentName(parentBeanDef.getBeanClassName());
childBeanDef.setBeanClass(Child.class);
applicationContext.registerBeanDefinition("parent", parentBeanDef);
applicationContext.registerBeanDefinition("child", childBeanDef);
System.out.println(applicationContext.getBeanDefinition("parent"));
System.out.println(applicationContext.getBeanDefinition("child")); //Generic bean with parent 'com.fsx.bean.Parent': class [com.fsx.bean.Child]; scope=;...
}
GenericBeanDefinition
源码实现非常的的简单,只增加了一个parentName
的属性值,其余的实现都在父类AbstractBeanDefinition
里
备注:若你是xml配置,最初被加载进来都是一个
GenericBeanDefinition
,之后再逐渐解析的。
ChildBeanDefinition
:子Bean定义信息,依赖于父类RootBeanDefinition
ChildBeanDefinition
是一种bean definition,它可以继承它父类的设置,即ChildBeanDefinition
对RootBeanDefinition
有一定的依赖关系。 (功能和GenericBeanDefinition
),所以此处忽略~
从spring 2.5 开始,提供了一个更好的注册bean definition类
GenericBeanDefinition
,所以以后推荐使用它。
RootBeanDefinition
:
一个RootBeanDefinition
定义表明它是一个可合并的bean definition:即在spring beanFactory运行期间,可以返回一个特定的bean。但在Spring2.5以后,我们绝大多数情况还是可以使用GenericBeanDefinition
来做。
我们非常熟悉的final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
这句代码,就是去合并parent的属性进来,这样体现了继承的强大。属性也才完整。
在 配置文件中可以定义父和子,父用RootBeanDefinition
表示, 而子用ChildBeanDefiniton
表示,而没有父的就使用 RootBeanDefinition
表示。下面看看源码:
//简单的说:在多继承体系中,RootBeanDefinition代表的是当前初始化类的父类的BeanDefinition 若没有父类,那就是它自己嘛
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保存了以下信息:
- 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
- Bean的注解(AnnotatedElement)
- 具体的工厂方法(Class类型),包括工厂方法的返回类型,工厂方法的Method对象
- 构造函数、构造函数形参类型
- Bean的class对象
可以看到,RootBeanDefinition与AbstractBeanDefinition是互补关系,RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本完善
接下来,再在看看AnnotatedBeanDefinition
的三个子类:
ScannedGenericBeanDefinition:存储@Component、@Service、@Controller等注解注释的类
它的源码很简单,就是多了一个属性:private final AnnotationMetadata metadata
用来存储扫描进来的Bean的一些注解信息。
// 实现了AnnotatedBeanDefinition 也继承了GenericBeanDefinition
public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
...
// 它只有一个构造函数:必须传入MetadataReader
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
this.metadata = metadataReader.getAnnotationMetadata();
setBeanClassName(this.metadata.getClassName());
}
}
AnnotatedGenericBeanDefinition
在基于注解驱动的Spring应用着,它使用得非常的多。因为获取注解信息非常的方便~
AnnotatedGenericBeanDefinition
只能用于已经被注册或被扫描到的类(否则你手动new一个,它就不在容器里了,那就脱离管理了)
使用案例:
public static void main(String[] args) {
AnnotatedBeanDefinition beanDefinition = new AnnotatedGenericBeanDefinition(RootConfig.class);
// 就这么一下子,就把注解们都拿到了,简直不要太方便,简直可以当工具类来用
Set<String> annotationTypes = beanDefinition.getMetadata().getAnnotationTypes();
System.out.println(annotationTypes); //[org.springframework.context.annotation.ComponentScan, org.springframework.context.annotation.Configuration]
System.out.println(beanDefinition.isSingleton()); //true
System.out.println(beanDefinition.getBeanClassName()); //com.config.RootConfig
}
源码参考;
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
private final AnnotationMetadata metadata;
@Nullable
private MethodMetadata factoryMethodMetadata;
/**
* Create a new AnnotatedGenericBeanDefinition for the given bean class.
* @param beanClass the loaded bean class 注意官方这个注释:已经加载进来了的Bean的Class
*/
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = new StandardAnnotationMetadata(beanClass, true);
}
//@since 3.1.1 此处传入AnnotationMetadata ,也得保证对应的class已经被loaded
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
Assert.notNull(metadata, "AnnotationMetadata must not be null");
if (metadata instanceof StandardAnnotationMetadata) {
setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
}
else {
setBeanClassName(metadata.getClassName());
}
this.metadata = metadata;
}
//@since 4.1.1 可以由指定的工厂方法产生这个Bean
public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) {
this(metadata);
Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null");
setFactoryMethodName(factoryMethodMetadata.getMethodName());
this.factoryMethodMetadata = factoryMethodMetadata;
}
@Override
public final AnnotationMetadata getMetadata() {
return this.metadata;
}
@Override
@Nullable
public final MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
}
}
ConfigurationClassBeanDefinition
首先需要注意的是,它是ConfigurationClassBeanDefinitionReader
的一个私有的静态内部类:这个类负责将@Bean注解的方法转换为对应的ConfigurationClassBeanDefinition类(非常的重要)
// 它直接继承自RootBeanDefinition
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {
... 源码和之前的差得不是太多,此处就不解释了
}
它有一些默认的设置处理如下:
- 如果@Bean注解没有指定bean的名字,默认会用方法的名字命名bean
- @Configuration注解的类会成为一个工厂类,而所有的@Bean注解的方法会成为工厂方法,通过工厂方法实例化Bean,而不是直接通过构造函数初始化(所以我们方法体里面可以很方便的书写逻辑。。。)
Spring
初始化时,会用GenericBeanDefinition
或是ConfigurationClassBeanDefinition
(用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition
。
BeanDefinitionBuilder:快速创建一个Bean定义
使用它的好处是,可以进行方法的连缀。 没有特殊指明,创建的都是GenericBeanDefinition
,源码非常的简单,下面只用个Deme看看即可
public class BeanDefinitionBuilder {
//=================创建一个Builder 没特殊指明,都是GenericBeanDefinition
public static BeanDefinitionBuilder genericBeanDefinition() {
return new BeanDefinitionBuilder(new GenericBeanDefinition());
}
....
public static BeanDefinitionBuilder rootBeanDefinition(String beanClassName) {
return rootBeanDefinition(beanClassName, null);
}
public static BeanDefinitionBuilder childBeanDefinition(String parentName) {
return new BeanDefinitionBuilder(new ChildBeanDefinition(parentName));
}
}
demo:
public static void main(String[] args) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Child.class)
.setRole(BeanDefinition.ROLE_APPLICATION)
.setScope(BeanDefinition.SCOPE_SINGLETON)
.addPropertyValue("name", "fsx")
.setLazyInit(false)
//Spring5.0后提供的,可以自己书写函数,在里面做任意事情
//bdf是个AbstractBeanDefinition
.applyCustomizers((bdf) -> {
AbstractBeanDefinition abdf = (AbstractBeanDefinition) bdf;
abdf.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_NO);
}).getRawBeanDefinition();
System.out.println(beanDefinition); //Generic bean: class [com.fsx.maintest.Child]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; d...
}
BeanDefinitionReader:该接口的作用就是加载 Bean
在 Spring 中,Bean 一般来说都在配置文件中定义。而在配置的路径由在 web.xml 中定义(还有全注解的方式)。所以加载 Bean 的步骤大致就是:
- 加载资源,通过配置文件的路径(Location)加载配置文件(Resource)
- 解析资源,通过解析配置文件的内容得到 Bean。
public interface BeanDefinitionReader {
// 得到Bean定义的register
BeanDefinitionRegistry getRegistry();
// 返回用于加载资源的 ResourceLoader(可以为null)
@Nullable
ResourceLoader getResourceLoader();
// 加载Bean的类加载器
@Nullable
ClassLoader getBeanClassLoader();
// 生成Bean名称的名字生成器(若没有指定名称的话,会调用它生成)
BeanNameGenerator getBeanNameGenerator();
// 核心方法,loadbean定义进来,然后注册到上面的register 里面去
int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException;
int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String location) throws BeanDefinitionStoreException;
int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException;
}
它的继承结构非常简单,一个抽象实现+3个具体实现
AbstractBeanDefinitionReader
它实现了一些基本的方法,但是核心方法loadBeanDefinitions
肯定是交给子类实现了
public abstract class AbstractBeanDefinitionReader implements EnvironmentCapable, BeanDefinitionReader {
private final BeanDefinitionRegistry registry;
@Nullable
private ResourceLoader resourceLoader;
@Nullable
private ClassLoader beanClassLoader;
// 会有环境变量
private Environment environment;
// 默认的名字生成器(类名首字母小写)
private BeanNameGenerator beanNameGenerator = new DefaultBeanNameGenerator();
// 此构造函数,会完成一些参数的初始化
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// Determine ResourceLoader to use.
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
} else {
// 注意这个处理~~~~
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
// Inherit Environment if possible
// 如果注册器里有环境变量,就用它的 否则new一个标准的~~~~ 它下面也提供了set方法可以设置
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
} else {
this.environment = new StandardEnvironment();
}
}
public void setEnvironment(Environment environment) {
Assert.notNull(environment, "Environment must not be null");
this.environment = environment;
}
public void setBeanNameGenerator(@Nullable BeanNameGenerator beanNameGenerator) {
this.beanNameGenerator = (beanNameGenerator != null ? beanNameGenerator : new DefaultBeanNameGenerator());
}
...
}
XmlBeanDefinitionReader
:从xml中加载Bean定义信息
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
...
}
我们注解配置中@Configuration
上也可以加上@ImportResource
导入外置的xml配置文件。它由此方法ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromImportedResources
处理,内部借助的就是XmlBeanDefinitionReader
去解析它的
PropertiesBeanDefinitionReader:直接从properties文件或者Map里加载Bean
由于它语法怪异,因此基本不适用了
GroovyBeanDefinitionReader:不在本文讨论中
可能有小伙伴问:那我们注解的@Bean以及@Component的这么些bean定义都是谁去加载的呢? 需要注意的是这个就不属于它了。
@Bean
都是@Configuration
配置类里,统一由ConfigurationClassParser#parse()
里去处理的(直接执行Method就行)@Component
这种组件统一由解析@ComponentScan的处理器的ComponentScanAnnotationParser
(借助ClassPathBeanDefinitionScanner
) 参考博文:【小家Spring】Spring解析@ComponentScan注解源码分析(ComponentScanAnnotationParser、ClassPathBeanDefinitionScanner)
总结
本编文章旨在讲解贯穿Spring IoC容器上下文的Bean定义接口、实现类等等。从设计中我们能发现,Spring的设计原则还是非常优秀的,单一职责的特性。 宁愿用扩展的方法多写类,也不会在Base里面加内容变得臃肿最终几乎笨重不可维护
有了这些基础,相信你在看Spring源码的时候又能更加顺畅很多了~共勉 (RootBeanDefinition、AnnotatedGenericBeanDefinition)