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个方法里面, 下篇博文 继续 分析


相关文章
|
6月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
|
10月前
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
589 70
|
监控 Java 应用服务中间件
SpringBoot是如何简化Spring开发的,以及SpringBoot的特性以及源码分析
Spring Boot 通过简化配置、自动配置和嵌入式服务器等特性,大大简化了 Spring 应用的开发过程。它通过提供一系列 `starter` 依赖和开箱即用的默认配置,使开发者能够更专注于业务逻辑而非繁琐的配置。Spring Boot 的自动配置机制和强大的 Actuator 功能进一步提升了开发效率和应用的可维护性。通过对其源码的分析,可以更深入地理解其内部工作机制,从而更好地利用其特性进行开发。
505 6
|
11月前
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
290 0
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
494 7
|
存储 Java Spring
【Spring】获取Bean对象需要哪些注解
@Conntroller,@Service,@Repository,@Component,@Configuration,关于Bean对象的五个常用注解
383 12
|
存储 Java 应用服务中间件
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
531 12
|
7月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1155 0
|
8月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
929 0

热门文章

最新文章