整体结构图

spring修改单例 spring修改beandefinition_缓存

1. BeanDefinition 用于保存 Bean 的相关信息,包括属性、构造方法参数、依赖的 Bean 名称及是否单例、延迟加载等,
它是实例化 Bean 的原材料,Spring 就是根据 BeanDefinition 中的信息实例化 Bean。
2. 我们获取对象的方式一般有两种,一种是手动直接 new;另一种是交给 Spring 管理,Spring 将管理的对象称之为 Bean,
容器会先实例化 Bean,然后自动注入,实例化的过程就需要依赖 BeanDefinition。
过程:BeanDefinition----通过一系列加工--->Bean

BeanDefinition

spring修改单例 spring修改beandefinition_spring_02

作用

  • 存储属性 : 基于接口 AttributeAccessor 实现
  • 存储元数据配置 : 基于 BeanMetadataElement 实现
  • 描述类的信息 : 包括Bean名称 , Primary 属性 , priority 配置 等等

总结其实就是一句话 : BeanDefinition 主要承载了Bean的元数据信息 ,同时描述了Bean在Spring体系中的加载方式 , 容器通过 BeanDefinition 中的配置来加载一个Bean

解析

BeanDefinition主要继承了两个接口,分别是AttributeAccessor,BeanMetadataElement;AttributeAccessor先不讲(AbstractBeanDefinition那里讲),我们先看看BeanMetadataElement,如图:

spring修改单例 spring修改beandefinition_spring修改单例_03

主要提供了获取源的方法,而什么是source呢?如图,这是包路径扫描时,将扫描的数据封装成ScannedGenericBeanDefinition的一部分操作,准备将获取到的source放入到BeanDefinition里:

spring修改单例 spring修改beandefinition_缓存_04

方法注释

属性

// 单例、原型标识符
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
// 标识 Bean 的类别,分别对应 用户定义的 Bean、来源于配置文件的 Bean、Spring 内部的 Bean
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;

方法

Bean的父类名称
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
Bean的 className
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
Bean的作用域
void setScope(@Nullable String scope);
@Nullable
String getScope();
Bean构造方法参数值、所有属性
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
    return !getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
    return !getPropertyValues().isEmpty();
}
Bean的类别

类别对应上面的三个属性值

void setRole(int role);
int getRole();
对bean定义的可读描述
void setDescription(@Nullable String description);
@Nullable
String getDescription();
Bean是否是单例、是否是非单例、是否是抽象的
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
该bean定义来自的资源的描述(用于在出现错误时显示上下文)
@Nullable
String getResourceDescription();
原始Bean定义
@Nullable
BeanDefinition getOriginatingBeanDefinition();
Bean是否懒加载(@Lazy)
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
Bean所依赖的其它Bean 名称(@DependsOn)
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
Bean是否可以自动注入(@Autowired)

只对 @Autowired 注解有效

void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
当前Bean是否为主要候选 Bean (@Primary)

当同一个接口有多个实现类时,通过该属性来配置某个 Bean 为主候选 Bean。

void setPrimary(boolean primary);
boolean isPrimary();
创建该Bean的工厂类
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
创建该Bean的工厂方法
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
初始化方法名称
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
销毁方法名称
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
获取*
ResolvableType getResolvableType();

AnnotatedBeanDefinition

作用

这个接口主要提供了对注解的支持

方法解析

获取注释元数据(以及基本类元数据)

AnnotationMetadata getMetadata();

获取此bean定义的工厂方法的元数据(如果有的话)

@Nullable
MethodMetadata getFactoryMethodMetadata();

AbstractBeanDefinition

spring修改单例 spring修改beandefinition_spring_05

解析

AbstractBeanDefinition基本上实现了BeanDefinition所有方法,除了这两个:

spring修改单例 spring修改beandefinition_spring_06

可以说,AbstractBeanDefinition重中之重,基本上所有的BeanDefinition都直接间接的继承了它。我们再看,除了BeanDefinition,AbstractBeanDefinition还继承了BeanMetadataAttributeAccessor类,这个类继承了AttributeAccessorSupport实现了BeanMetadataElement:

spring修改单例 spring修改beandefinition_java_07

如果你已经阅读了BeanDefinition那部分的内容,那么你大概也知道了BeanMetadataElement的作用,以及source的样子,所以我们主要讲一下AttributeAccessorSupport这个类,AttributeAccessorSupport是唯一实现了AttributeAccessor接口的类,具有了操作属性的功能,并且里面拥有一个map,用于存放属性:

spring修改单例 spring修改beandefinition_spring修改单例_08

而属性具体在什么时候用到了呢?目前就我了解的一个作用就是存放标志位,用于标识做过了哪些操作。例如下面是注解 载入BeanDefinition时部分代码,红框部分,就是从属性map里面获取加载标识位,判断BeanDefinition是否有加载过:

spring修改单例 spring修改beandefinition_缓存_09

像调用ConfigurationClassUtils#checkConfigurationClassCandidate(校验Bean是否是配置类)时,在期间就又加了一些标志位:

spring修改单例 spring修改beandefinition_spring修改单例_10

属性解析

常量

//默认的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的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
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);
//是否是合成类(是不是应用自定义的,例如生成AOP代理时,会用到某些辅助类,这些辅助类不是应用自定义的,这个就是合成类)
//创建AOP时候为true
private boolean synthetic = false;
//Bean的角色,为用户自定义Bean
private int role = BeanDefinition.ROLE_APPLICATION;
// Bean的描述信息
@Nullable
private String description;
// 这个Bean哪儿来的
@Nullable
private Resource resource;
构造相关
//记录构造函数注入属性,对应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;
工厂相关
//我理解为通过这个函数的逻辑初始化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;

ChildBeanDefinition

已经废弃了,被GenericBeanDefinition替代了,不多赘述了。

GenericBeanDefinition

解析

GenericBeanDefinition在继承AbstractBeanDefinition的基础上,实现了getParentName和setParentName这两个方法,可以设置父类BeanDefinition的名称:

spring修改单例 spring修改beandefinition_spring_11

一般来说,这个类是用于XML加载Bean定义信息时,会将读取到的数据封装成GenericBeanDefinition,PS:你首先要知道xml方式是通过XmlBeanDefinitionReader解析器加载xml里的所有数据的。

加载路径:

XmlBeanDefinitionReader#loadBeanDefinitions(EncodedResource encodedResource)
	-->doLoadBeanDefinitions(InputSource inputSource, Resource resource)
	-->registerBeanDefinitions(Document doc, Resource resource)
-->DefaultBeanDefinitionDocumentReader#registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
	-->doRegisterBeanDefinitions(Element root)
	-->parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
	-->parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
	-->processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
-->BeanDefinitionParserDelegate#parseBeanDefinitionElement(Element ele)
	-->parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)
	-->parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean)
	-->createBeanDefinition(@Nullable String className, @Nullable String parentName)
-->BeanDefinitionReaderUtils#createBeanDefinition(@Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader)

最终,如图,创建了GenericBeanDefinition:

spring修改单例 spring修改beandefinition_构造函数_12

RootBeanDefinition

作用

主要在 Bean 实例化时使用,为了方便实例化操作,提供了大量的缓存字段,方便重复实例化时减少工作量。它可以单独作为一个 BeanDefinition,也可以作为其他 BeanDefinition 的父类。

属性解析

//BeanDefinitionHolder存储有Bean的名称、别名、BeanDefinition
@Nullable
private BeanDefinitionHolder decoratedDefinition;
//是java反射包的接口,通过它可以查看Bean的注解信息
@Nullable
private AnnotatedElement qualifiedElement;
//允许缓存
boolean allowCaching = true;
//从字面上理解:工厂方法是否唯一
boolean isFactoryMethodUnique = false;
//封装了java.lang.reflect.Type,提供了泛型相关的操作
@Nullable
volatile ResolvableType targetType;
//缓存class,表明RootBeanDefinition存储哪个类的信息
@Nullable
volatile Class<?> resolvedTargetType;
//缓存工厂方法的返回类型
@Nullable
volatile ResolvableType factoryMethodReturnType;
//缓存工厂方法
@Nullable
volatile Method factoryMethodToIntrospect;
//以下四个变量的锁
final Object constructorArgumentLock = new Object();
//缓存已经解析的构造函数或是工厂方法,Executable是Method、Constructor类型的父类
@Nullable
Executable resolvedConstructorOrFactoryMethod;
//表明构造函数参数是否解析完毕
boolean constructorArgumentsResolved = false;
//缓存完全解析的构造函数参数
@Nullable
Object[] resolvedConstructorArguments;
//缓存待解析的构造函数参数,即还没有找到对应的实例,可以理解为还没有注入依赖的形参(我的理解)
@Nullable
Object[] preparedConstructorArguments;
//以下两个变量的锁
final Object postProcessingLock = new Object();
//表明是否被MergedBeanDefinitionPostProcessor处理过
boolean postProcessed = false;
//在生成代理的时候会使用,表明是否已经生成代理
@Nullable
volatile Boolean beforeInstantiationResolved;

以下三个属性是外部管理的方法集合(配置、初始化、銷毀),似乎可以缓存自动装配对象的值

// 实际缓存的类型是Constructor、Field、Method类型
@Nullable
private Set<Member> externallyManagedConfigMembers;
@Nullable
// InitializingBean中的init回调函数名——afterPropertiesSet会在这里记录,以便进行生命周期回调
private Set<String> externallyManagedInitMethods;

@Nullable
// DisposableBean的destroy回调函数名——destroy会在这里记录,以便进行生命周期回调
private Set<String> externallyManagedDestroyMethods;

补充

MergedBeanDefinition:这个词其实不是一个官方词,但是很接近,该词主要是用来表示 “合并的 bean 定义”,因为每次都写 “合并的 bean 定义” 有点太绕口,因此我在之后的注释或解析中或统一使用 MergedBeanDefinition 来表示 “合并的 bean 定义”。
之所以称之为 “合并的”,是因为存在 “子定义” 和 “父定义” 的情况。对于一个 bean 定义来说,可能存在以下几种情况:
该 BeanDefinition 存在 “父定义”:首先使用 “父定义” 的参数构建一个 RootBeanDefinition,然后再使用该 BeanDefinition 的参数来进行覆盖。
该 BeanDefinition 不存在 “父定义”,并且该 BeanDefinition 的类型是 RootBeanDefinition:直接返回该 RootBeanDefinition 的一个克隆。
该 BeanDefinition 不存在 “父定义”,但是该 BeanDefinition 的类型不是 RootBeanDefinition:使用该 BeanDefinition 的参数构建一个 RootBeanDefinition。
之所以区分出2和3,是因为通常 BeanDefinition 在之前加载到 BeanFactory 中的时候,通常是被封装成 GenericBeanDefinition 或 ScannedGenericBeanDefinition,但是从这边之后 bean 的后续流程处理都是针对 RootBeanDefinition,因此在这边会统一将 BeanDefinition 转换成 RootBeanDefinition。

AnnotatedGenericBeanDefinition

属性

  • AnnotationMetadata:主要对 Bean 的注解信息进行操作,如:获取当前 Bean 标注的所有注解、判断是否包含指定注解。
  • MethodMetadata:方法的元数据类。提供获取方法名称、此方法所属类的全类名、是否是抽象方法、判断是否是静态方法、判断是否是final方法等。

spring修改单例 spring修改beandefinition_构造函数_13

解析

AnnotatedGenericBeanDefinition主要用于描述标注@Configuration注解的Bean。PS:需要明白注解方式载入BeanDefinition是通过工厂后置处理器ConfigurationClassPostProcessor实现的。

ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(Set<ConfigurationClass> configurationModel)
	loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator)
	registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass)

spring修改单例 spring修改beandefinition_构造函数_14

ScannedGenericBeanDefinition

该类继承自 GenericBeanDefinition,并实现了AnnotatedBeanDefinition接口。这个BeanDefinition用来描述标注@Component注解的 Bean,其派生注解如 @Service@Controller也同理.PS:需要明白注解方式载入BeanDefinition是通过工厂后置处理器ConfigurationClassPostProcessor实现的。

解析路径:

ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)
ConfigurationClassParser#parse(Set<BeanDefinitionHolder> configCandidates)
	parse(AnnotationMetadata metadata, String beanName)
	processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter)
	doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
ComponentScanAnnotationParser#parse(AnnotationAttributes componentScan, final String declaringClass)
ClassPathBeanDefinitionScanner#doScan(String... basePackages)
ClassPathScanningCandidateComponentProvider#findCandidateComponents(String basePackage)
	scanCandidateComponents(String basePackage)

spring修改单例 spring修改beandefinition_java_15

ConfigurationClassBeanDefinition

该类继承自 RootBeanDefinition ,并实现了 AnnotatedBeanDefinition 接口。这个BeanDefinition用来描述在标注 @Configuration 注解的类中,通过 @Bean 注解实例化的 Bean 。PS:需要明白注解方式载入BeanDefinition是通过工厂后置处理器ConfigurationClassPostProcessor实现的。

解析路径:

ConfigurationClassPostProcessor#processConfigBeanDefinitions(BeanDefinitionRegistry registry)
ConfigurationClassBeanDefinitionReader#loadBeanDefinitions(Set<ConfigurationClass> configurationModel)
	loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator)
	loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod)

spring修改单例 spring修改beandefinition_spring_16

注解相关

懒加载

对某个bean进行延迟加载(延迟到在第一次调用的时候实例化)

@Lazy注解只对单例有用

解决Spring 循环依赖的一个简单方法就是对一个Bean使用延时加载

初始化

@PostConstruct,InitializingBean,以及SmartInitializingSingleton

@PostConstruct是最先被执行的,然后是InitializingBean,最后是SmartInitializingSingleton

构造方法 >@PostContruct > afterPropertiesSet()> init-method