Spring5源码 - 03 普通对象对应的BeanDefinition是如何存入DefaultListableBeanFactory#beanDefinitionMap 源码分析

简介: Spring5源码 - 03 普通对象对应的BeanDefinition是如何存入DefaultListableBeanFactory#beanDefinitionMap 源码分析

20200914143739548.png

Pre


接上文 Spring5源码 - 02 Bean和Java对象的区别与猜想验证BeanDefinition


我们分析了流程, 也从理论上描述了 普通对象 ----- BeanDefinition ------Bean对象之间的关联,提到了一个BeanDefinition的Map集合 (我们称之为 bdmap ,后面都用这个简称代替 ),


那从源码里面怎么体现出来bdmap 的呢?


本篇博文将带你一一掀开


Spring处理bdmap 的理念


因为这个bdmap 对应Spring太重要了,不仅要处理用户配置的扫描包下的bean,还有一点更重要Spring内置的bean 也需要依靠这个bdmap .

如果这个bdmap 完全交给开发者来处理,比如你把这个map中的数据给remove掉了,等等之类的不可信任的操作,结果可想而知,所以Spring封装了一些API,仅允许开发者通过Spring提供的API来修改bdmap .


源码分析


那我们来看下Spring是如何来封装的这个API呢?

接上文中的 BeanFactoryPostProcessor Bean工厂后置处理器


20200916093823293.png

ConfigurableListableBeanFactory 这个 beanFactory对象 是Spring封装的用于提供给开发者修改BeanDefinition的一个接口类。


20200916103343614.png


提供了 getBeanDefinition 方法

beanFactory.getBeanDefinition("artisan1");


ctrl + alt + b 打开实现类 DefaultListableBeanFactory


20200916094239600.png


我们来看下 定义 beanDefinitionMap

  private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);


Spring也是用的Map来存储的 ~

那我要看 spring是如何把BeanDefinition放到这个 beanDefinitionMap 中的,那我就需要重点观察 beanDefinitionMap 这个对象,Spring是在什么时候赋值的 .


我们知道了 DefaultListableBeanFactory 有个属性 是 beanDefinitionMap

先找DefaultListableBeanFactory

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);


AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);


20200916100458443.png

跟进去构造函数

  public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    register(componentClasses);
    refresh();
  }


this() : 调用无参构造函数,会先调用父类GenericApplicationContext的构造函数 ,父类的构造函数里面就是初始化DefaultListableBeanFactory,并且赋值给beanFactory . 本类的构造函数里面,初始化了一个读取器:AnnotatedBeanDefinitionReader read,一个扫描器ClassPathBeanDefinitionScanner scanner . scanner的用处不是很大,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的 .


register(componentClasses): 注册配置类 即 AppConfig.class


refresh() : 容器刷新,这个是最核心的方法。 很重要


回到this(),我们来看下源码

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {}

父类的构造函数

20200924073100745.png

实例化DefaultListableBeanFactory


20200924073341874.png

DefaultListableBeanFactory非常最重要, 主要就是用来生产和获得Bean的


接着子类的构造函数


20200924070329538.png


this.reader = new AnnotatedBeanDefinitionReader(this); 初始化一个Bean读取器


this.scanner = new ClassPathBeanDefinitionScanner(this);初始化一个扫描器,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的


继续看 new AnnotatedBeanDefinitionReader(this) 实例化建BeanDefinition读取器

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
      BeanDefinitionRegistry registry, @Nullable Object source) {
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
      if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
        //注册了实现Order接口的排序器
        beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
      }
      //设置@AutoWired的候选的解析器
      if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
      }
    }
    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
    /**
     * 为我们容器中注册了解析我们配置类的后置处理器ConfigurationClassPostProcessor
     * 名字叫:org.springframework.context.annotation.internalConfigurationAnnotationProcessor
     */
    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));
    }
    /**
     * 为我们容器中注册了处理@Autowired 注解的处理器AutowiredAnnotationBeanPostProcessor
     * 名字叫:org.springframework.context.annotation.internalAutowiredAnnotationProcessor
     */
    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));
    }
    /**
     * 为我们容器中注册处理@Required属性的注解处理器RequiredAnnotationBeanPostProcessor
     * 名字叫:org.springframework.context.annotation.internalRequiredAnnotationProcessor
     */
    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));
    }
    /**
     * 为我们容器注册处理JSR规范的注解处理器CommonAnnotationBeanPostProcessor
     * org.springframework.context.annotation.internalCommonAnnotationProcessor
     */
    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));
    }
    /**
     * 处理jpa注解的处理器org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor
     */
    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));
    }
    /**
     * 处理监听方法的注解解析器EventListenerMethodProcessor
     */
    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;
  }


主要工作

  1. 注册内置BeanPostProcessor 开天辟地的元勋Bean
  2. 注册相关的BeanDefinition

Step1 : this(); 【初始化BeanFactory】


20200916101037527.png


没有呢?我们知道实例化子类,父类也会被初始化,那往上找找吧

20200916101154471.png


可以看到是在父类GenericApplicationContext中初始化的DefaultListableBeanFactory

这样的话,我们把断点打在下面一行 register(componentClasses)上,观察this 中的对象 如下


20200916104718113.png


现在是有默认的Spring初始化的时候自己的BeanDefinition , 没有我们自己的bd ,那就继续走,看看这个beanDefinitionMap什么时候会发生变化~


register(componentClasses); 【注册bean】

先看结论

image.png


说明这一步就完成了 从 普通对象 (注册配置类)------- BeanDefinition ----------存入到 bdMap中的操作


接下来分析下核心源码

流程如下


image.png


如上 ,这个流程完成后, DefaultListableBeanFactory#beanDefinitionMap 就有了new AnnotationConfigApplicationContext(AppConfig.class)


入参中的 AppConfig.class 对应的Bean了


20200916114040422.png


refresh();


那这个AppConfig配置的扫描包下的bean,什么时候初始化呢? 那就是refresh这个方法了 ,下文继续

先看一眼,结论

20200916113731935.png


这个方法太重要了,一共有12个方法里面, 下篇博文 继续 分析


相关文章
|
8天前
|
Java 应用服务中间件 Nacos
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
21 0
|
11天前
|
监控 数据可视化 安全
一套成熟的Spring Cloud智慧工地平台源码,自主版权,开箱即用
这是一套基于Spring Cloud的智慧工地管理平台源码,具备自主版权,易于使用。平台运用现代技术如物联网、大数据等改进工地管理,服务包括建设各方,提供人员、车辆、视频监控等七大维度的管理。特色在于可视化管理、智能报警、移动办公和分布计算存储。功能涵盖劳务实名制管理、智能考勤、视频监控AI识别、危大工程监控、环境监测、材料管理和进度管理等,实现工地安全、高效的智慧化管理。
|
1月前
|
消息中间件 NoSQL Java
Spring Cloud项目实战Spring Cloud视频教程 含源码
Spring Cloud项目实战Spring Cloud视频教程 含源码
30 1
|
1天前
|
设计模式 安全 Java
【初学者慎入】Spring源码中的16种设计模式实现
以上是威哥给大家整理了16种常见的设计模式在 Spring 源码中的运用,学习 Spring 源码成为了 Java 程序员的标配,你还知道Spring 中哪些源码中运用了设计模式,欢迎留言与威哥交流。
|
4天前
|
XML Java 数据格式
手写spring第八章-定义标记类型Aware接口,实现感知容器对象
手写spring第八章-定义标记类型Aware接口,实现感知容器对象
4 0
|
4天前
|
XML Java 数据格式
手写spring第七章-完成便捷实现bean对象初始化和销毁方法
手写spring第七章-完成便捷实现bean对象初始化和销毁方法
6 0
|
6天前
|
XML 人工智能 Java
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
Spring Bean名称生成规则(含源码解析、自定义Spring Bean名称方式)
|
12天前
|
Java Maven Nacos
Spring Cloud Eureka 服务注册和服务发现超详细(附加--源码实现案例--及实现逻辑图)
Spring Cloud Eureka 服务注册和服务发现超详细(附加--源码实现案例--及实现逻辑图)
24 0
|
13天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
13天前
|
人工智能 监控 安全
Java+Spring Cloud +Vue+UniApp微服务智慧工地云平台源码
视频监控系统、人员实名制与分账制管理系统、车辆管理系统、环境监测系统、大型设备监测(龙门吊、塔吊、升降机、卸料平台等)、用电监测系统、基坑监测系统、AI算法分析(安全帽佩戴、火焰识别、周界报警、人员聚众报警、升降机超载报警)、安全培训、设备监测。
20 4