zl程序教程

您现在的位置是:首页 >  IT要闻

当前栏目

spring源码学习笔记2——基于注解生成BeanDefinition的过程解析

2023-04-18 12:33:00 时间

一丶前言

1.AnnotationConfigApplicationContext是什么

独立的应用程序上下文,接受组件类作为输入——特别是 @Configuration 注释的类,但也有普通的 @Component 类型和使用 javax.inject 注解的 JSR-330 兼容类。 允许使用 register(Class...) 逐个注册类,以及使用 scan(String...) 进行类路径扫描。 在多个@Configuration 类的情况下,后面的类中定义的@Bean 方法将覆盖早期类中定义的方法。 这可以用来通过额外的 @Configuration 类故意覆盖某些 bean 定义

2.类图

相比于ClassPathXmlApplicationContext ,AnnotationConfigApplicationContext多实现了一个接口AnnotationConfigRegistry,AnnotationConfigRegistry有两个方法

二丶两个重要的构造方法

和ClassPathXmlApplicationContext 不同的在于,在refresh之前会执行register or scan

三丶register

AnnotatedBeanDefinitionReader 看名称和 XmlBeanDefinitionReader 差不多,理论上应该实现了BeanDefinitionReader接口,但是却没有(虚晃一枪),最终调用到doRegisterBean方法

1.@Condition注解生效

 ConditionEvaluator用于执行Condition注解的内容

2.@Scope 注解解析

这里使用AnnotationScopeMetadataResolver 来解析@Scope 把Scope注解上的内容 封装到ScopeMetadata 中,默认为单例,且proxyMode为不使用代理类

3.获取bean 名称

使用 AnnotationBeanNameGenerator 来获取bean名称,如果当前的BeanDefinition是 AnnotatedBeanDefinition(说明是由注解注入bean的方式)会解析@Componet(或者它的符合注解上的value值)(还支持javax.annotation.ManagedBean,javax.inject.Named)

如果没有标注bean名称,那么会生成默认的Bean名称,当前类名首字母小写对于的值

4.解析@Lazy,@Primary,@DependsOn,@Role,@Description 注解

解析注解并且设置AnnotatedBeanDefinition 对应的属性,@Lazy 表示是否懒加载(用到的时候再加载)@Primary在存在多个符合条件的bean可以注入的时候,标注@Primary注解的bean会优先被注入,@DependsOn表示这个bean的注入依赖于其他bean

5.执行BeanDefinitionCustomizer

BeanDefinitionCustomizer 接口是Spring给我们留下的一个扩展点,可以通过实现这个接口,对BeanDefinition进行自定义的设置

6.@Scope注解的proxyMode

如果标注proxyMode为ScopedProxyMode.TARGET_CLASS 表示为当前类生成CGLIB代理类,ScopedProxyMode.INTERFACES表示使用JDK动态代理,取代用户定义的Bean,如果是No 那么直接返回原BeanDefinition注册到容器

调用 ScopedProxyCreator.createScopedProxy方法,具体的做法是会把用户的BeadDefinition拷贝一份,但是还会由如下操作

7.注册BeanDefinition到容器

和xml相同,都是维护一张Map 保存Bean 名称和BeanDefinition的关系,并且维护别名

四丶scan

扫描的任务委托给ClassPathBeanDefinitionScanner 完成,主要逻辑在scanCandidateComponents方法中

1.isCandidateComponent

主要逻辑如下:


这里的excludeFilters为空集合,includeFilters存在一个AnnotationTypeFilter,可以根据类上面的注解判断是否符合条件,判断逻辑如下

一般considerInherited 为false,considerInterfaces也为false

最终判断一个类是否是候选组件的方法实在AnnotationTypeFilter的matchSelf方法

这里是否考虑合并注解是指

2.转换为ScannedGenericBeanDefinition,并且判断是否符合条件

3.后续的操作

  1. 解析Scope和register方法类似,都是获取注解上的Scope并设置,后面如果proxyMode不为no 还会复制当前BeanDefinition,并且设置不作为依赖注入的候选bean

  2. 解析@Lazy,@Primary,@DependsOn,@Role,@Description 注解

  3. 还会检查是否重复bean名称

    如果存在名称相同的BeanDefinition,这里有个判断是否兼容的逻辑,就是BeanDefinition数据来源(比如来自注解)来源相同,或者当前BeanDefinition和存在的BeanDefinition相同 那么视为兼容,否则抛出异常

!

五丶AnnotationConfigApplicationContext 的refresh操作

AnnotationConfigApplicationContext 的refresh操作后续不会加载BeanDefinition了,register or scan 负责BeanDefinition的加载了