Spring 的IoC容器中核心定义之------BeanDefinition深入分析

Spring 的IoC容器中核心定义之------BeanDefinition深入分析

image-20200921161139509

Spring IoC 容器 Management 一个或多个 bean。这些 bean 是使用您提供给容器的配置元数据创建的(例如,以 XML <bean/>定义的形式)。

在容器本身内,这些 bean 定义表示为BeanDefinition对象,其中包含(除其他信息外)以下元数据:

  • 包限定的类名:通常,定义了 Bean 的实际实现类。
  • Bean 行为配置元素,用于声明 Bean 在容器中的行为(作用域,生命周期回调等)。
  • 引用其他 bean 进行其工作所需的 bean。这些引用也称为协作者或依赖项。
  • 要在新创建的对象中设置的其他配置设置,例如,池的大小限制或在 Management 连接池的 bean 中使用的连接数。

该元数据转换为构成每个 bean 定义的一组属性。下表描述了这些属性:

表 1. bean 定义

Property Explained in…
Class Instantiating Beans
Name Naming Beans
Scope Bean Scopes
Constructor arguments Dependency Injection
Properties Dependency Injection
Autowiring mode Autowiring Collaborators
延迟初始化模式 Lazy-initialized Beans
Initialization method Initialization Callbacks
Destruction method Destruction Callbacks

除了包含有关如何创建特定 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));

现在可以开始做菜了吗?其实还不行,因为还没有菜谱(不知道做什么菜,怎么做~) BeanDefinitionRegistryBeanFactory就是这份菜谱,BeanDefinitionRegistry抽象出bean的注册逻辑,而BeanFactory则抽象出了bean的管理逻辑 各个BeanFactory的实现类就具体承担了bean的注册以及管理工作

DefaultListableBeanFactory作为一个比较通用的BeanFactory实现,它同时也实现了BeanDefinitionRegistry接口,因此它就承担了Bean的注册管理工作

最后我们总结一下比喻关系:
  1. Spring IoC容器:餐馆(服务员)
  2. BeanDefinitionRegistry和 BeanFactory:菜谱
  3. BeanDefinitionRegistry:抽象出来的,向菜谱里注册菜(的管理器)
  4. BeanFactory:抽象出来的,管理这些菜谱(的管理器)
  5. BeanDefinition:原料(做菜所需要的原料)
  6. DefaultListableBeanFactory:具体实施者(具体注册菜谱、做菜的实施者)
  7. 依赖注入的使用者:客户(进店吃饭的人)

BeanDefinition源码分析

总体的 Java Class Diagrams 图:

image-20200921162411586

因为它继承了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定义旗下三大实现类:ScannedGenericBeanDefinitionConfigurationClassBeanDefinitionAnnotatedGenericBeanDefinition

抽象实现: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的某些默认设置(例如默认为单例等)。

从上图可以看出,接下俩需要看具体衍生出来的实现类了,先看RootBeanDefinitionChildBeanDefinitionGenericBeanDefinition。他们都是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,它可以继承它父类的设置,即ChildBeanDefinitionRootBeanDefinition有一定的依赖关系。 (功能和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保存了以下信息:

  1. 定义了id、别名与Bean的对应关系(BeanDefinitionHolder)
  2. Bean的注解(AnnotatedElement)
  3. 具体的工厂方法(Class类型),包括工厂方法的返回类型,工厂方法的Method对象
  4. 构造函数、构造函数形参类型
  5. 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 的步骤大致就是:

  1. 加载资源,通过配置文件的路径(Location)加载配置文件(Resource)
  2. 解析资源,通过解析配置文件的内容得到 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个具体实现

image-20200921162658227

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)

posted @ 2020-09-21 16:31  天宇轩-王  阅读(690)  评论(0编辑  收藏  举报