【深入理解Spring系列4】BeanDefinition

前情提要

Spring Bean的 四种装配模式外,还有一种自动策略。

当只有一个 构造方法,并且构造方法里有参数。
会进行 aurowireConstructor(beanName, mdb, ctors, args)

  • spring扫描不能直接new的方C法

@DependsOn

@Prototype 执行的时候new

所以需要先解析验证。

scan-parse(会变成BeaDefinition)-validate(info)-new(开始spring的生命周期)

可以这么理解:

beanDefinition之于Spring
相当于class之于java对象

  • 常量(BeanDefinition)
  • SCOPE_SINGLETON

ROLE_APPLICATION

setParentName

//自动装配候选对象 ,被装配
setAutowireCandidate
//候选对象最高级
setPrimary

BeanDefinition所有属性都能找到与之匹配的 xml配置。

ac.getBean(XXX);是从DefaultSingletonBeanRegistry.singletonObjects.get(XXX)

  • abstractApplicationContext

abstractApplicationContext.refresh()

1
2
3
4
5
//这里初始化对象。还未装配
finishBeanFactoryInitialization(beanFactory);

//这里装配。
finishRefresh()
  1. 扫描
  2. parse
  3. validate
  4. life 遍历map得到BeanDefinition实例化。

BeanDefinition

各方法说明:

setPrimary:
多个接口实现的时候,自动注入候选的时候排第一。

  • 关键父类
    AbstractBeanDefinition

ChildBeanDefinition,RootBeanDefinition Spring 2.5的时候用

GenericBeanDefinition
现在常用。

xml 配置里的描述的就是 beanDefinition的属性。
spring容器会进行扫描。扫描后会根据bendefinition里描述的进行实例化。

abstract = true 必须要有 beanClass

  • RootBeanDefinition

减少不同 bean配置多种相同相同属性值的 工作量 abstract=true

parent = ‘xxx’

spring 2.5之前有这种写法。后面更方便了用扫描,用标签。

问题:RootBeanDefinition也有 setParentName(),为什么要多一个ChildBeanDefinition ?

RootBeanDefinition一般作为父出现,或者一般BD出现。但是不作为子BD出现。
为什么要这样规定?为什么设置Root的Parent要抛出异常?

合并BeanDefinition?

  • AnnotatedBeanDefinitionReader

作用:解析@Configuration 这标签会去扫描

1
2
3
4
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}

beanReader = AnnotatedBeanDefinitionReader(this);
把 配置的AppConfig 变成 BeanDefinition

其他的 要完成扫描的时候去new 其他BD.

1
this.reader = new AnnotatedBeanDefinitionReader(this);  这么写是为了后面能通过 context.register.registBean(标签) 来扩展自定义标签。

注意这里是为了扩展,spring启动的时候并不是用这个scaner去扫描。
实际上用的是,在BeanDefinitionRegistry这个后置处理器。

ConfigutationClassPostProcessor.postProcessBanDefinitionRegistry(registry)

->
这里找到 registry里初始化的BeanDefinition,进行parse
ConfigurationClassParser.parse(Set candidates)
这个方法里会判断 参数是否实现了 AnnotatedBeanDefinition

bd instanceof AnnotatedBeanDefinition

ConfigurationClassParser.processConfigurationClass

//这段很有意思,扫描结束后会将sourceClass设置为null。说明所有的BeanDefinition都扫描出来了。

1
2
3
4
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
1
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)

doProcessConfigurationClass
这里是实现。
实际识别了@Component @ComponentScan @ImportSource 等标签。

然后在
ComponentScanAnnotationParser
类里的
public Set parse(AnnotationAttributes componentScan, final String declaringClass)

进行实际的扫描,先new 出了
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,

再判断各种includerFilter excluderFilter
最后根据 标签配置的 包路径进行文件扫描。
从而扫描出Beandefinition 放到BeanDeinitionMap

小总结:
Beandefinition决定了spring 中Bean的各种特征。
class-beandefinition-springbean。
通过beandefinition spring定义了一套 spring bean的属性特征。

GenericBeanDefinition追加了setBeanClass