说说Spring如何加载注册BeanDefinition

BeanDefinition定义

Bean的定义信息是Spring容器的一个核心概念,核心接口是BeanDefinition

Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构。

不管是是通过xml配置文件的<Bean>标签,还是通过注解配置的@Bean,它最终都会被解析成一个Bean定义信息(对象),最后我们的Bean工厂就会根据这份Bean的定义信息,对bean进行实例化、初始化等等操作。

BeanDefinition源码分析

总体的类图:

因为它继承了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能够检索并修改属性值和别的bean的元数据,例如:PropertyPlaceHolderConfigurer

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有一定的依赖关系。

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,源码非常的简单,下面只用个Demo看看即可:

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个具体实现

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

可能有人会问:我们注解的@Bean以及@Component的这么些bean定义都是谁去加载的呢? 

其实,@Bean都是@Configuration配置类里,统一由ConfigurationClassParser#parse()里去处理的(直接执行Method就行)

@Component这种组件统一由解析@ComponentScan的处理器的ComponentScanAnnotationParser(借助ClassPathBeanDefinitionScanner) 。

如何加载bean定义信息

Spring IOC容器启动过程中,会加载BeanDefinition。

spring beanDefinition加载,在方法obtainFreshBeanFactory中完成(org.springframework.context.support.AbstractApplicationContext#refresh)

org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory方法

createBeanFactory:创建容器,会获取parent容器作为参数传入

xml配置的使用org.springframework.web.context.support.XmlWebApplicationContext#loadBeanDefinitions

注解的使用org.springframework.web.context.support.AnnotationConfigWebApplicationContext#loadBeanDefinitions

这里先以 xml 配置为例,创建beanDefinitionReader

获取resource,也就是配置的xml文件

将resource读入,解析成document对象

主要方法在这,传入doc节点,开始解析

parseDefaultElement方法解析标签import、alias、bean、beans四种

接下来,我们将着重讲解两个非常关键的类:AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner。它俩完成对Bean信息的加载。

AnnotationConfigApplicationContext(spring-context包下)的继承图谱如下:

需要注意的是,我们在Tomcat等web环境下的容器类为:AnnotationConfigWebApplicationContext,它在spring-web包下

那到底是什么时候创建了AnnotationConfigWebApplicationContext实例呢?可以参考 :聊聊Spring容器(含父子容器)的启动过程分析

org.springframework.web.context.support.AnnotationConfigWebApplicationContext#loadBeanDefinitions

@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
    AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
    ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);

    BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
    if (beanNameGenerator != null) {
        reader.setBeanNameGenerator(beanNameGenerator);
        scanner.setBeanNameGenerator(beanNameGenerator);
        beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
    }

    ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
    if (scopeMetadataResolver != null) {
        reader.setScopeMetadataResolver(scopeMetadataResolver);
        scanner.setScopeMetadataResolver(scopeMetadataResolver);
    }

    if (!this.componentClasses.isEmpty()) {
        if (logger.isDebugEnabled()) {
            logger.debug("Registering component classes: [" +
                         StringUtils.collectionToCommaDelimitedString(this.componentClasses) + "]");
        }
        reader.register(ClassUtils.toClassArray(this.componentClasses)); //① 
    }

    if (!this.basePackages.isEmpty()) {
        if (logger.isDebugEnabled()) {
            logger.debug("Scanning base packages: [" +
                         StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
        }
        scanner.scan(StringUtils.toStringArray(this.basePackages)); //②
    }

    String[] configLocations = getConfigLocations();
    if (configLocations != null) {
        for (String configLocation : configLocations) {
            try {
                Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
                if (logger.isTraceEnabled()) {
                    logger.trace("Registering [" + configLocation + "]");
                }
                reader.register(clazz);
            }
            catch (ClassNotFoundException ex) {
                if (logger.isTraceEnabled()) {
                    logger.trace("Could not load class for config location [" + configLocation +
                                 "] - trying package scan. " + ex);
                }
                int count = scanner.scan(configLocation);
                if (count == 0 && logger.isDebugEnabled()) {
                    logger.debug("No component classes found for specified class/package [" + configLocation + "]");
                }
            }
        }
    }
}

AnnotatedBeanDefinitionReader初始化,构造器如下:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    this.registry = registry;

    //ConditionEvaluator完成条件注解的判断,在后面的Spring Boot中有大量的应用
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    //这句会把一些自动注解处理器加入到AnnotationConfigApplicationContext下的BeanFactory的BeanDefinitions中  具体见下面
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

AnnotationConfigUtils#registerAnnotationConfigProcessors()

我们要用一些注解比如:@Autowired/@Required/@Resource都依赖于各种各样的BeanPostProcessor来解析(AutowiredAnnotation、RequiredAnnotation、CommonAnnotationBeanPostProcessor等等)。

但是像这种非常常用的,让调用者自己去申明,显然使用起来就过重了。所以Spring为我们提供了一种极为方便注册这些BeanPostProcessor的方式(若是xml方式,配置<context:annotation-config/>,若是全注解驱动的ApplicationContext,就默认会执行)

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, null);
}

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
    	BeanDefinitionRegistry registry, @Nullable Object source) {
    
    // 把我们的beanFactory从registry里解析出来
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
    	if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
    		beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
    	}
    	// 相当于如果没有这个AutowireCandidateResolver,就给设置一份ContextAnnotationAutowireCandidateResolver
    	if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
    		beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
    	}
    }
    
    //这里初始长度放4  是因为大多数情况下,我们只会注册4个BeanPostProcessor 如下(不多说了)
    // BeanDefinitionHolder解释:持有name和aliases,为注册做准备
    // Spring 4.2之后这个改成6我觉得更准确点
    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4);

    if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    	RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
    	def.setSource(source);
    	beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    	RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    	def.setSource(source);
    	beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    	RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
    	def.setSource(source);
    	beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    // 支持JSR-250的一些注解:@Resource、@PostConstruct、@PreDestroy等
    if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    	RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
    	def.setSource(source);
    	beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
    }

    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    // 若导入了对JPA的支持,那就注册JPA相关注解的处理器
    if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    	RootBeanDefinition def = new RootBeanDefinition();
    	try {
    		def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
    				AnnotationConfigUtils.class.getClassLoader()));
    	}
    	catch (ClassNotFoundException ex) {
    		throw new IllegalStateException(
    				"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
    	}
    	def.setSource(source);
    	beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
    }


    // 下面两个类,是Spring4.2之后加入进来的,为了更好的使用Spring的事件而提供支持 
    // 支持了@EventListener注解,我们可以通过此注解更方便的监听事件了(Spring4.2之后)
    // 具体这个Processor和ListenerFactory怎么起作用的,且听事件专题分解
    if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
    	RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
    	def.setSource(source);
    	beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
    }
    if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
    	RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
    	def.setSource(source);
    	beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
    }

    return beanDefs;
}

我们发现:内部定义的class都是带internal的:

(1) ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor处理器,BeanDefinitionRegistryPostProcessor的处理方法能处理@Configuration等注解。ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法内部处理@Configuration,@Import,@ImportResource和类内部的@Bean。

ConfigurationClassPostProcessor类继承了BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor类继承了BeanFactoryPostProcessor。
通过BeanDefinitionRegistryPostProcessor可以创建一个特别后置处理器来将BeanDefinition添加到BeanDefinitionRegistry中。它和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的时候有个钩子让我们加入一些自定义操作;而BeanDefinitionRegistryPostProcessor可以让我们在BeanDefinition中添加一些自定义操作。在Mybatis与Spring的整合中,就利用到了BeanDefinitionRegistryPostProcessor来对Mapper的BeanDefinition进行了后置的自定义处理。

(2) AutowiredAnnotationBeanPostProcessor是用来处理@Autowired注解和@Value注解的

(3) RequiredAnnotationBeanPostProcessor这是用来处理@Required注解

(4) CommonAnnotationBeanPostProcessor提供对JSR-250规范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。

(5) EventListenerMethodProcessor提供@PersistenceContext的支持。

(6) EventListenerMethodProcessor提供@ EventListener 的支持。@ EventListener实在spring4.2之后出现的,可以在一个Bean的方法上使用@EventListener注解来自动注册一个ApplicationListener。

到此AnnotatedBeanDefinitionReader初始化完毕。

总结一下,AnnotatedBeanDefinitionReader读取器用来加载class类型的配置,在它初始化的时候,会预先注册一些BeanPostProcessor和BeanFactoryPostProcessor,这些处理器会在接下来的spring初始化流程中被调用。

ClassPathBeanDefinitionScanner的初始化:

跟踪构造函数的重载,最终都到这里:

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
		Environment environment, @Nullable ResourceLoader resourceLoader) {

    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;
    
    //useDefaultFilters为true,所以此处一般都会执行
    // 当然我们也可以设置为false,比如@ComponentScan里就可以设置为false,只扫描指定的注解/类等等
    if (useDefaultFilters) {
    	registerDefaultFilters();
    }
    // 设置环境
    setEnvironment(environment);
    // 详情如下:  这里resourceLoader传值,还是我们的工厂。否则为null
    setResourceLoader(resourceLoader);
}

registerDefaultFilters()

protected void registerDefaultFilters() {
    // 这里需要注意,默认情况下都是添加了@Component这个注解的
    //(相当于@Service @Controller @Respository等都会扫描,因为这些注解都属于@Component)  另外@Configuration也属于哦
    this.includeFilters.add(new AnnotationTypeFilter(Component.class));
    ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();

    //下面两个 是兼容JSR-250的@ManagedBean和330的@Named注解
    try {
        this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
        logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
    } catch (ClassNotFoundException ex) {
        // JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
    }
    try {
        this.includeFilters.add(new AnnotationTypeFilter(
            ((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
        logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
    } catch (ClassNotFoundException ex) {
        // JSR-330 API not available - simply skip.
    }

    // 所以,如果你想Spring连你自定义的注解都扫描,自己实现一个AnnotationTypeFilter就可以啦
}

ClassPathBeanDefinitionScanner继承于ClassPathScanningCandidateComponentProvider,它内部维护有两个final类型的List:这两个对象在执行本类的scanCandidateComponents()方法时就会起作用。

//includeFilters中的就是满足过滤规则的
private final List<TypeFilter> includeFilters = new LinkedList<>();
//excludeFilters则是不满足过滤规则的
private final List<TypeFilter> excludeFilters = new LinkedList<>();

ClassPathScanningCandidateComponentProvider#setResourceLoader

为ResourcePatternResolver,MetadataReaderFactory和CandidateComponentsIndex设定初始值。

@Override
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
    this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
    this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
    // Spring5以后才有这句,优化了bean扫描
    this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}

说明:若要使用Spring5 的这个功能,需要添加如下包。这样子当工程重新编译的时候(编译期),会在自动生成META-INF/spring-components。然后我们在启动用@ComponentScan扫描时,直接读取这个文件即可,极大的提高了Spring启动的速度。而这期间,可以使用Spring5.0最新提供的注解@Indexed来配合使用。
需要注意的是:这种方式也是存在缺陷的,具体缺陷请参考官方文档:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-scanning-index

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-indexer</artifactId>
    <version>5.0.7.RELEASE</version>
    <optional>true</optional>
</dependency>

然后在运行后会生成一个 META-INF/spring.components 的文件,之后只要运行工程发现这个文件都会直接使用它。可以通过环境变量或工程根目录的spring.properties中设置spring.index.ignore=ture来禁用这个功能 (这个功能如果没有什么明确的需求,慎重使用,会提高工程的管理成本。)

  • ResourcePatternResolver是一个接口,继承了ResourceLoader,可以用来获取Resource 实例。返回的实例为PathMatchingResourcePatternResolver类型
  • MetadataReaderFactory用于解析资源信息对应的元数据,这里返回的实例为:CachingMetadataReaderFactory,带有缓存
  • CandidateComponentsIndexLoader.loadIndex () 方法是spring5.0以后加入的新特性,Spring Framework 5 改进了扫描和识别组件的方法,使大型项目的性能得到提升。(具体是通过编译器完成扫描,并且往本地写索引,然后启动的时候再去扫描索引即可的思路)

至此,ClassPathBeanDefinitionScanner初始化完毕,总结一下:

ClassPathBeanDefinitionScanner是一个扫描指定类路径中注解Bean定义的扫描器,在它初始化的时候,会初始化一些需要被扫描的注解,初始化用于加载包下的资源的Loader。

AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner的初始化是spring上线文初始化的起点,很多预加载的类会在spring接下来的初始化中发挥重要作用。

实际逻辑在doRegisterBean()此方法上:org.springframework.context.annotation.AnnotatedBeanDefinitionReader#doRegisterBean 

private <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
		@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
	
    // 先把此实体类型转换为一个BeanDefinition
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    //abd.getMetadata() 元数据包括注解信息、是否内部类、类Class基本信息等等
    // 此处由conditionEvaluator#shouldSkip去过滤,此Class是否是配置类。
    // 大体逻辑为:必须有@Configuration修饰。然后解析一些Condition注解,看是否排除~
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
    	return;
    }

    abd.setInstanceSupplier(instanceSupplier);
    // 解析Scope
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    abd.setScope(scopeMetadata.getScopeName());
    // 得到Bean的名称 一般为首字母小写(此处为AnnotationBeanNameGenerator)
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

    // 设定一些注解默认值,如lazy、Primary等等
    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    // 解析qualifiers,若有此注解  则primary都成为true了
    if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
    		}
    		else if (Lazy.class == qualifier) {
    			abd.setLazyInit(true);
    		}
    		else {
    			abd.addQualifier(new AutowireCandidateQualifier(qualifier));
    		}
    	}
    }
    // 自定义定制信息(一般都不需要)
    for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
    	customizer.customize(abd);
    }

    // 下面位解析Scope是否需要代理,最后把这个Bean注册进去
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

包扫描: org.springframework.context.annotation.ClassPathBeanDefinitionScanner#scan

下面就是重点看看doScan()方法:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    // 装载扫描到的Bean
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    for (String basePackage : basePackages) {

    	// 这个方法是最重点,把扫描到的Bean就放进来了(比如此处只有RootConfig一个Bean定义,是个配置类)
    	// 这个是重点,会把该包下面所有的Bean都扫描进去。Spring5和一下的处理方式不一样哦~
    	Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    	for (BeanDefinition candidate : candidates) {
    		// 拿到Scope元数据:此处为singleton
    		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
    		candidate.setScope(scopeMetadata.getScopeName());
    		// 生成Bean的名称,默认为首字母小写。此处为"rootConfig"
    		String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

    		// 此处为扫描的Bean,为ScannedGenericBeanDefinition,所以肯定为true
    		// 因此进来,执行postProcessBeanDefinition(对Bean定义信息做)   如下详解
    		// 注意:只是添加些默认的Bean定义信息,并不是执行后置处理器~~~
    		if (candidate instanceof AbstractBeanDefinition) {
    			postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
    		}
    		// 显然,此处也是true  也是完善比如Bean上的一些注解信息:比如@Lazy、@Primary、@DependsOn、@Role、@Description   @Role注解用于Bean的分类分组,没有太大的作用
    		if (candidate instanceof AnnotatedBeanDefinition) {
    			AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
    		}
    		// 检查这个Bean  比如
    		//如果dao包(一般配置的basePakage是这个)下的类是符合mybaits要求的则向spring IOC容器中注册它的BeanDefinition  所以这步检查第三方Bean的时候有必要检查一下
    		if (checkCandidate(beanName, candidate)) {
    			BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
    			
    			//AnnotationConfigUtils类的applyScopedProxyMode方法根据注解Bean定义类中配置的作用域@Scope注解的值,为Bean定义应用相应的代理模式,主要是在Spring面向切面编程(AOP)中使用
    			definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    			beanDefinitions.add(definitionHolder);

    			// 注意 注意 注意:这里已经吧Bean注册进去工厂了,所有doScan()方法不接收返回值,也是没有任何问题的。。。。
    			registerBeanDefinition(definitionHolder, this.registry);
    		}
    	}
    }
    return beanDefinitions;
}

ClassPathScanningCandidateComponentProvider#findCandidateComponents 

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    // 上面说过了CandidateComponentsIndex是Spring5提供的优化扫描的功能
    // 显然这里编译器我们没有写META-INF/spring.components索引文件,所以此处不会执行Spring5 的扫描方式,所以我暂时不看了(超大型项目才会使用Spring5的方式)
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
    	return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    } else {
    	// Spring 5之前的方式(绝大多数情况下,都是此方式)
    	return scanCandidateComponents(basePackage);
    }
}

scanCandidateComponents:根据basePackage扫描候选的组件们(非常重要)

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
    Set<BeanDefinition> candidates = new LinkedHashSet<>();
    try {
    	// 1.根据指定包名 生成包搜索路径
    	//通过观察resolveBasePackage()方法的实现, 我们可以在设置basePackage时, 使用形如${}的占位符, Spring会在这里进行替换 只要在Enviroment里面就行
    	// 本次值为:classpath*:com/fsx/config/**/*.class
    	String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
    			resolveBasePackage(basePackage) + '/' + this.resourcePattern;
    	
    	//2. 资源加载器 加载搜索路径下的 所有class 转换为 Resource[]
    	// 拿着上面的路径,就可以getResources获取出所有的.class类,这个很强大~~~
    	// 真正干事的为:PathMatchingResourcePatternResolver#getResources方法
    	// 此处能扫描到两个类AppConfig(普通类,没任何注解标注)和RootConfig。所以接下里就是要解析类上的注解,以及过滤掉不是候选的类(比如AppConfig)
    	
    	// 注意:这里会拿到类路径下(不包含jar包内的)的所有的.class文件 可能有上百个,然后后面再交给后面进行筛选~~~~~~~~~~~~~~~~(这个方法,其实我们也可以使用)
    	// 当然和getResourcePatternResolver和这个模版有关
    	Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);    
    	// 记录日志(下面我把打印日志地方都删除)
    	boolean traceEnabled = logger.isTraceEnabled();
    	boolean debugEnabled = logger.isDebugEnabled();    
    	// 接下来的这个for循环:就是把一个个的resource组装成
    	for (Resource resource : resources) {
    		//文件必须可读 否则直接返回空了
    		if (resource.isReadable()) {
    			try {    
    				//读取类的 注解信息 和 类信息 ,两大信息储存到  MetadataReader
    				MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
    		
    				// 根据TypeFilter过滤排除组件。因为AppConfig没有标准@Component或者子注解,所以肯定不属于候选组件  返回false
    				// 注意:这里一般(默认处理的情况下)标注了默认注解的才会true,什么叫默认注解呢?就是@Component或者派生注解。还有javax....的,这里省略啦
    				if (isCandidateComponent(metadataReader)) {
    				
    					//把符合条件的 类转换成 BeanDefinition
    					ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
    					sbd.setResource(resource);
    					sbd.setSource(resource);
    					
    					// 再次判断 如果是实体类 返回true,如果是抽象类,但是抽象方法 被 @Lookup 注解注释返回true (注意 这个和上面那个是重载的方法) 
    					// 这和上面是个重载方法  个人觉得旨在处理循环引用以及@Lookup上
    					if (isCandidateComponent(sbd)) {
    						candidates.add(sbd);
    					}
    				}
    			} 
    		}
    	}
    }
    return candidates;
}

// 备注:此时ComponentScan这个注解还并没有解析

ClassPathBeanDefinitionScanner#postProcessBeanDefinition

protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
    // 位Bean定义 执行些默认的信息
    // BeanDefinitionDefaults是个标准的javaBean,有一些默认值
    beanDefinition.applyDefaults(this.beanDefinitionDefaults);

    // 自动依赖注入 匹配路径(此处为null,不进来)
    if (this.autowireCandidatePatterns != null) {
    	beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
    }
}

//AbstractBeanDefinition#applyDefaults:

public void applyDefaults(BeanDefinitionDefaults defaults) {
    setLazyInit(defaults.isLazyInit());
    setAutowireMode(defaults.getAutowireMode());
    setDependencyCheck(defaults.getDependencyCheck());
    setInitMethodName(defaults.getInitMethodName());
    setEnforceInitMethod(false);
    setDestroyMethodName(defaults.getDestroyMethodName());
    setEnforceDestroyMethod(false);
}

就这样,扫描的Bean就全部注册完成了(若你的Config比较多的情况下,用扫描的方式更加简单些~)

BeanDefinition注册中心BeanDefinitionRegistry

BeanDefinitionRegistry是一个接口, 实现了AliasRegistry接口, 定义了一些对 bean的常用操作。

它有大概如下功能:

  • 以Map<String, BeanDefinition>的形式注册bean
  • 根据beanName 删除和获取 beanDefiniation
  • 得到持有的beanDefiniation的数目
  • 根据beanName 判断是否包含beanDefiniation
// 它继承自 AliasRegistry 
public interface BeanDefinitionRegistry extends AliasRegistry {

    // 关键 -> 往注册表中注册一个新的 BeanDefinition 实例 
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException;
    // 移除注册表中已注册的 BeanDefinition 实例
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    // 从注册中心取得指定的 BeanDefinition 实例
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    // 判断 BeanDefinition 实例是否在注册表中(是否注册)
    boolean containsBeanDefinition(String beanName);
    
    // 取得注册表中所有 BeanDefinition 实例的 beanName(标识)
    String[] getBeanDefinitionNames();
    // 返回注册表中 BeanDefinition 实例的数量
    int getBeanDefinitionCount();
    // beanName(标识)是否被占用
    boolean isBeanNameInUse(String beanName);
}

下面看看它们的继承关系:

可以看出,它的默认实现类,主要有三个:SimpleBeanDefinitionRegistry、DefaultListableBeanFactory、GenericApplicationContext

SimpleBeanDefinitionRegistry

它是默认的一个实现方式,也是一个非常简单的实现。存储用的是ConcurrentHashMap ,可以保证线程安全

// @since 2.5.2可以看到提供得还是比较晚的
// AliasRegistry和SimpleAliasRegistry都是@since 2.5.2之后才有的~~~
public class SimpleBeanDefinitionRegistry extends SimpleAliasRegistry implements BeanDefinitionRegistry {
    
    // 采用的ConcurrentHashMap来存储注册进来的Bean定义信息~~~~
    /** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
    ... // 各种实现都异常的简单,都是操作map
    // 这里只简单说说这两个方法

    // 需要注意的是:如果没有Bean定义,是抛出的异常,而不是返回null这点需要注意
    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
    	BeanDefinition bd = this.beanDefinitionMap.get(beanName);
    	if (bd == null) {
    		throw new NoSuchBeanDefinitionException(beanName);
    	}
    	return bd;
    }
    // beanName是个已存在的别名,或者已经包含此Bean定义了,那就证明在使用了嘛
    // 它比单纯的containsBeanDefinition()范围更大些~~~
    @Override
    public boolean isBeanNameInUse(String beanName) {
    	return isAlias(beanName) || containsBeanDefinition(beanName);
    }
}

DefaultListableBeanFactory

该类是 BeanDefinitionRegistry 接口的基本实现类,但同时也实现其他了接口的功能,这里关注注册 BeanDefinition 实例的相关方法。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    ...
    /** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    // 保存所有的Bean名称
    /** List of bean definition names, in registration order */
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

    // 注册Bean定义信息~~
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    		throws BeanDefinitionStoreException {
    	...
    	BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    	// 如果不为null,说明这个beanName对应的Bean定义信息已经存在了~~~~~
    	if (oldBeanDefinition != null) {
    		// 是否允许覆盖(默认是true 表示允许的)
    		if (!isAllowBeanDefinitionOverriding()) {
    			// 抛异常
    		}
    		// 若允许覆盖  那还得比较下role  如果新进来的这个Bean的role更大			
    		// 比如老的是ROLE_APPLICATION(0)  新的是ROLE_INFRASTRUCTURE(2) 
    		// 最终会执行到put,但是此处输出一个warn日志,告知你的bean被覆盖啦~~~~~~~(我们自己覆盖Spring框架内的bean显然就不需要warn提示了)
    		else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
    			// 仅仅输出一个logger.warn
    		}
    		// 最终会执行put,但是内容还不相同  那就提醒一个info信息吧
    		else if (!beanDefinition.equals(oldBeanDefinition)) {
    			// 输出一个info信息
    		}
    		else {
    			// 输出一个debug信息
    		}
    		// 最终添加进去 (哪怕已经存在了~) 
    		// 从这里能看出Spring对日志输出的一个优秀处理,方便我们定位问题~~~
    		this.beanDefinitionMap.put(beanName, beanDefinition);
    		// 请注意:这里beanName并没有再add了,因为已经存在了  没必要了嘛
    	}
    	else {
    		// hasBeanCreationStarted:表示已经存在bean开始创建了(开始getBean()了吧~~~)
    		if (hasBeanCreationStarted()) {
    			// 注册过程需要synchronized,保证数据的一致性	synchronized (this.beanDefinitionMap) {
    				this.beanDefinitionMap.put(beanName, beanDefinition); // 放进去
    				List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
    				updatedDefinitions.addAll(this.beanDefinitionNames);
    				updatedDefinitions.add(beanName);
    				this.beanDefinitionNames = updatedDefinitions;
    		
    				// 
    				if (this.manualSingletonNames.contains(beanName)) {
    					Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
    					updatedSingletons.remove(beanName);
    					this.manualSingletonNames = updatedSingletons;
    				}
    			}
    		}
    		else {
    			// Still in startup registration phase
    			// 表示仍然在启动  注册的状态~~~就很好处理了 put仅需,名字add进去
    			this.beanDefinitionMap.put(beanName, beanDefinition);
    			this.beanDefinitionNames.add(beanName);
    			
    			// 手动注册的BeanNames里面移除~~~ 因为有Bean定义信息了,所以现在不是手动直接注册的Bean单例~~~~
    			this.manualSingletonNames.remove(beanName);
    		}

    		// 这里的意思是:但凡你新增了一个新的Bean定义信息,之前已经冻结的就清空呗~~~
    		this.frozenBeanDefinitionNames = null;
    	}
    	
    	// 最后异步很有意思:老的bean定义信息不为null(beanName已经存在了),或者这个beanName直接是一个单例Bean了~
    	if (oldBeanDefinition != null || containsSingleton(beanName)) {
    		// 做清理工作:
    		// clearMergedBeanDefinition(beanName)
    		// destroySingleton(beanName);  销毁这个单例Bean  因为有了该bean定义信息  最终还是会创建的
    		// Reset all bean definitions that have the given bean as parent (recursively).  处理该Bean定义的getParentName  有相同的也得做清楚  所以这里是个递归
    		resetBeanDefinition(beanName);
    	}
    }    
    @Override
    public void removeBeanDefinition(String beanName) throws 		NoSuchBeanDefinitionException {
    	// 移除整体上比较简单:beanDefinitionMap.remove
    	// beanDefinitionNames.remove
    	// resetBeanDefinition(beanName);

    	BeanDefinition bd = this.beanDefinitionMap.remove(beanName);
    	// 这里发现移除,若这个Bean定义本来就不存在,事抛异常,而不是返回null 需要注意~~~~
    	if (bd == null) {
    		throw new NoSuchBeanDefinitionException(beanName);
    	}

    	if (hasBeanCreationStarted()) {
    		synchronized (this.beanDefinitionMap) {
    			List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames);
    			updatedDefinitions.remove(beanName);
    			this.beanDefinitionNames = updatedDefinitions;
    		}
    	} else {
    		this.beanDefinitionNames.remove(beanName);
    	}
    	this.frozenBeanDefinitionNames = null;
    	resetBeanDefinition(beanName);
    }

    // 这个实现非常的简单,直接从map里拿
    @Override
    public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
    	BeanDefinition bd = this.beanDefinitionMap.get(beanName);
    	if (bd == null) {
    		throw new NoSuchBeanDefinitionException(beanName);
    	}
    	return bd;
    }

    @Override
    public boolean containsBeanDefinition(String beanName) {
    	return this.beanDefinitionMap.containsKey(beanName);
    }
    @Override
    public int getBeanDefinitionCount() {
    	return this.beanDefinitionMap.size();
    }
    @Override
    public String[] getBeanDefinitionNames() {
    	String[] frozenNames = this.frozenBeanDefinitionNames;
    	if (frozenNames != null) {
    		return frozenNames.clone();
    	}
    	else {
    		return StringUtils.toStringArray(this.beanDefinitionNames);
    	}
    }
    
    // ==========这个方法非常有意思:它是间接的实现的===============
    // 因为BeanDefinitionRegistry有这个方法,而它的父类AbstractBeanFactory也有这个方法,所以一步小心,就间接的实现了这个接口方法
    public boolean isBeanNameInUse(String beanName) {
    	// 增加了一个hasDependentBean(beanName);  或者这个BeanName是依赖的Bean 也会让位被使用了
    	return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName);
    }
}

DefaultListableBeanFactory它对Bean定义注册中心接口的实现逻辑。

XmlBeanFactory

它是DefaultListableBeanFactory的子类。Spring3.1之后建议用DefaultListableBeanFactory代替

@Deprecated
@SuppressWarnings({"serial", "all"})
public class XmlBeanFactory extends DefaultListableBeanFactory {
    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

    // 此处resource资源事传一个xml的文件资源~~~~
    // parentBeanFactory:父工厂~~~
    public XmlBeanFactory(Resource resource) throws BeansException {
    	this(resource, null);
    }
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
    	super(parentBeanFactory);
    	this.reader.loadBeanDefinitions(resource);
    }
}

GenericApplicationContext

这是一个通用的Spring上下文了,之前也说到了,它基本什么都得靠自己手动来处理:

public static void main(String[] args) {
    GenericApplicationContext ctx = new GenericApplicationContext();
    //手动使用XmlBeanDefinitionReader
    XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
    //加载ClassPathResource
    xmlReader.loadBeanDefinitions(new ClassPathResource("spring.xml"));

    //=========我们可议执行多次loadBeanDefinitions,从不同的地方把Bean定义信息给拿过来,最后再启动容器即可==============
     备注:此处的bean都采用properties的方式去配置(基本没人会这么使用了)
    //PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
    //propReader.loadBeanDefinitions(new ClassPathResource("spring.properties"));

    //调用Refresh方法 启动容器(这个都需要手动  哈哈)
    ctx.refresh();

    //和其他ApplicationContext方法一样的使用方式
    System.out.println(ctx.getBean("person")); //com.fsx.bean.Person@1068e947
}

spring.xml如下:

<bean id="person" class="com.fsx.bean.Person"/>

因为是手动档,对API的使用有一定的门槛,因此我们一般情况下不会直接使用它。但是它有两个子类我们是比较熟悉的。

GenericXmlApplicationContext

利用XML来配置Bean的定义信息,借助XmlBeanDefinitionReader去读取~~~

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

    // 这个很重要:它持有一个DefaultListableBeanFactory的引用
    private final DefaultListableBeanFactory beanFactory;
	
    // 所以下面所有的 BeanDefinitionRegistry 相关的方法都是委托给beanFactory去做了的,因此省略~~~
}

AbstractApplicationContext最终也是委托给getBeanFactory()去做这些事。而最终的实现都是它:DefaultListableBeanFactory
备注:AnnotationConfigWebApplicationContext、XmlWebApplicationContext都继承自AbstractRefreshableConfigApplicationContext,从而也最终继承了AbstractApplicationContext。 

 AnnotationConfigApplicationContext

注解驱动去扫描Bean的定义信息。先用ClassPathBeanDefinitionScanner把文件都扫描进来,然后用AnnotatedBeanDefinitionReader去load没有里面的Bean定义信息。

说明:由上面的继承关系可以看出,上文顶层接口ApplicationContext是不提供直接注册Bean定义信息、删除等一些操作的。因为ApplicationContext它并没有实现此接口BeanDefinitionRegistry,但是它继承了接口ListableBeanFactory,所以它有如下三个能力:

boolean containsBeanDefinition(String beanName);
int getBeanDefinitionCount();
String[] getBeanDefinitionNames();

ApplicationContext体系里只有子体系GenericApplicationContext下才能直接操作注册中心。比如常用的:GenericXmlApplicationContext和AnnotationConfigApplicationContext。 

手动注册BeanDefinition(编程方式注册Bean定义) 

手动注册bean的两种方式:

  1. 实现ImportBeanDefinitionRegistrar
  2. 实现BeanDefinitionRegistryPostProcessor

有个重要实现类ConfigurationClassPostProcessor,它是来处理@Configuration配置文件的。它最终就是解析配置文件里的@Import、@Bean等,然后把定义信息都注册进去~~~

 

 

posted @   残城碎梦  阅读(159)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示