【小家Spring】Spring容器加载Bean定义信息的两员大将:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner(上)

简介: 【小家Spring】Spring容器加载Bean定义信息的两员大将:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner(上)

前言

在分析Spring IOC容器启动流程的时候,在加载Bean定义信息BeanDefinition的时候,用到了两个非常关键的类:AnnotatedBeanDefinitionReader和ClassPathBeanDefinitionScanner。它俩完成对Bean信息的加载。


因此为了更加顺畅的去理解Bean的加载的一个过程,本文主要介绍Spring的这两员大将的一个初始化过程,以及它俩扮演的重要角色

环境准备



因为我们只需要了解Bean的加载,所以只需要启动一个容器就行,并不需要web环境,因此本文用一个相对简单的环境,来进行讲解,如下:

  @ComponentScan(value = "com.fsx", excludeFilters = {
          @Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
          //排除掉web容器的配置文件,否则会重复扫描
          @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {AppConfig.class}),
  })
  @Configuration
  public class RootConfig {
      @Bean
      public Parent parent() {
          return new Parent();
      }
  }
    public static void main(String[] args) {
        // 备注:此处只能用RootConfig,而不能AppConfig(启动报错),因为它要web容器支持,比如Tomcat
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
        System.out.println(applicationContext.getBean(Parent.class)); //com.fsx.bean.Parent@639c2c1d
    }


环境准备好了,启动之后也能正常打印出Bean的信息。因此接下来,就是要去分析源码,看看这两大工具起的作用


IOC容器加载Bean定义信息分析


AnnotationConfigApplicationContext(spring-context包下)的继承图谱如下:


需要注意的是,我们在Tomcat等web环境下的容器类为:AnnotationConfigWebApplicationContext,它在spring-web包下

image.png


Spring容器里通过BeanDefinition对象来表示Bean,BeanDefinition描述了Bean的配置信息。

而BeanDefinitionRegistry接口提供了向容器注册,删除,获取BeanDefinition对象的方法。


简单来说,BeanDefinitionRegistry可以用来管理BeanDefinition,所以理解AnnotationConfigApplicationContext很关键,它是spring加载bean,管理bean的最重要的类。


源码跟踪:


  public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    // 把该配置类(们)注册进来
    register(annotatedClasses);
    // 容器启动核心方法
    refresh();
  }


this()如下:

  //AnnotatedBeanDefinitionReader是一个读取注解的Bean读取器,这里将this传了进去。
  public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
  }
  //从上面这个构造函数可以顺便提一句:如果你仅仅是这样ApplicationContext applicationContext = new AnnotationConfigApplicationContext()
  // 容器是不会启动的(也就是不会执行refresh()的),这时候需要自己之后再手动启动容器

进而再看看register()方法:


  public void register(Class<?>... annotatedClasses) {
    Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
    this.reader.register(annotatedClasses);
  }
  public void register(Class<?>... annotatedClasses) {
    for (Class<?> annotatedClass : annotatedClasses) {
      registerBean(annotatedClass);
    }
  }
  public void registerBean(Class<?> annotatedClass) {
    doRegisterBean(annotatedClass, null, null, null);
  }


实际逻辑在doRegisterBean()此方法上:

  <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
      @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
    // 先把此实体类型转换为一个BeanDefinition
    AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    //abd.getMetadata() 元数据包括注解信息、是否内部类、类Class基本信息等等
    // 此处由conditionEvaluator#shouldSkip去过滤,此Class是否是配置类。
    // 大体逻辑为:必须有@Configuration修饰。然后解析一些Condition注解,看是否排除~
    if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
      return;
    }
    abd.setInstanceSupplier(instanceSupplier);
    // 解析Scope
    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
    abd.setScope(scopeMetadata.getScopeName());
    // 得到Bean的名称 一般为首字母小写(此处为AnnotationBeanNameGenerator)
    String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    // 设定一些注解默认值,如lazy、Primary等等
    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    // 解析qualifiers,若有此注解  则primary都成为true了
    if (qualifiers != null) {
      for (Class<? extends Annotation> qualifier : qualifiers) {
        if (Primary.class == qualifier) {
          abd.setPrimary(true);
        }
        else if (Lazy.class == qualifier) {
          abd.setLazyInit(true);
        }
        else {
          abd.addQualifier(new AutowireCandidateQualifier(qualifier));
        }
      }
    }
    // 自定义定制信息(一般都不需要)
    for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
      customizer.customize(abd);
    }
    // 下面位解析Scope是否需要代理,最后把这个Bean注册进去
    BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
    definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
  }


AnnotatedBeanDefinitionReader初始化,构造器如下


  public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
    this(registry, getOrCreateEnvironment(registry));
  }
  public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    this.registry = registry;
    //ConditionEvaluator完成条件注解的判断,在后面的Spring Boot中有大量的应用
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
    //这句会把一些自动注解处理器加入到AnnotationConfigApplicationContext下的BeanFactory的BeanDefinitions中  具体见下面
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
  }



这里将AnnotationConfigApplicationContext注册为管理BeanDefinition的BeanDefinitionRegistry,也就是说,spring中bean的管理完全交给了AnnotationConfigApplicationContext


AnnotationConfigUtils#registerAnnotationConfigProcessors()

我们要用一些注解比如:@Autowired/@Required/@Resource都依赖于各种各样的BeanPostProcessor来解析(AutowiredAnnotation、RequiredAnnotation、CommonAnnotationBeanPostProcessor等等)


但是向这种非常常用的,让调用者自己去申明,显然使用起来就过重了。所以Spring为我们提供了一种极为方便注册这些BeanPostProcessor的方式(若是xml方式,配置<context:annotation- config/>,若是全注解驱动的ApplicationContext,就默认会执行)


  public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
    registerAnnotationConfigProcessors(registry, null);
  }
  public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
      BeanDefinitionRegistry registry, @Nullable Object source) {
    // 把我们的beanFactory从registry里解析出来
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
      if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
        beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
      }
      // 相当于如果没有这个AutowireCandidateResolver,就给设置一份ContextAnnotationAutowireCandidateResolver
      if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
        beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
      }
    }
    //这里初始长度放4  是因为大多数情况下,我们只会注册4个BeanPostProcessor 如下(不多说了)
    // BeanDefinitionHolder解释:持有name和aliases,为注册做准备
    // Spring 4.2之后这个改成6我觉得更准确点
    Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4);
    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));
    }
    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));
    }
    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));
    }
    // Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
    // 支持JSR-250的一些注解:@Resource、@PostConstruct、@PreDestroy等
    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));
    }
    // Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
    // 若导入了对JPA的支持,那就注册JPA相关注解的处理器
    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));
    }
    // 下面两个类,是Spring4.2之后加入进来的,为了更好的使用Spring的事件而提供支持 
    // 支持了@EventListener注解,我们可以通过此注解更方便的监听事件了(Spring4.2之后)
    // 具体这个Processor和ListenerFactory怎么起作用的,且听事件专题分解
    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;
  }



相关文章
|
5月前
|
XML Java 测试技术
《深入理解Spring》:IoC容器核心原理与实战
Spring IoC通过控制反转与依赖注入实现对象间的解耦,由容器统一管理Bean的生命周期与依赖关系。支持XML、注解和Java配置三种方式,结合作用域、条件化配置与循环依赖处理等机制,提升应用的可维护性与可测试性,是现代Java开发的核心基石。
|
5月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
615 2
|
12月前
|
Java 测试技术 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——少量配置信息的情形
本课主要讲解Spring Boot项目中的属性配置方法。在实际开发中,测试与生产环境的配置往往不同,因此不应将配置信息硬编码在代码中,而应使用配置文件管理,如`application.yml`。例如,在微服务架构下,可通过配置文件设置调用其他服务的地址(如订单服务端口8002),并利用`@Value`注解在代码中读取这些配置值。这种方式使项目更灵活,便于后续修改和维护。
271 0
|
7月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
1294 10
|
8月前
|
人工智能 安全 Java
Spring Boot yml 配置敏感信息加密
本文介绍了如何在 Spring Boot 项目中使用 Jasypt 实现配置文件加密,包含添加依赖、配置密钥、生成加密值、在配置中使用加密值及验证步骤,并提供了注意事项,确保敏感信息的安全管理。
1446 1
|
10月前
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
266 18
|
XML Java 数据格式
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
京东一面:spring ioc容器本质是什么? ioc容器启动的步骤有哪些?
|
XML Java 数据格式
Spring容器的本质
本文主要讨论Spring容器最核心的机制,用最少的代码讲清楚Spring容器的本质。
|
12月前
|
Java 微服务 Spring
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——少量配置信息的情形
在微服务架构中,随着业务复杂度增加,项目可能需要调用多个微服务。为避免使用`@Value`注解逐一引入配置的繁琐,可通过定义配置类(如`MicroServiceUrl`)并结合`@ConfigurationProperties`注解实现批量管理。此方法需在配置文件中设置微服务地址(如订单、用户、购物车服务),并通过`@Component`将配置类纳入Spring容器。最后,在Controller中通过`@Resource`注入配置类即可便捷使用,提升代码可维护性。
238 0
|
监控 JavaScript 数据可视化
建筑施工一体化信息管理平台源码,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
智慧工地云平台是专为建筑施工领域打造的一体化信息管理平台,利用大数据、云计算、物联网等技术,实现施工区域各系统数据汇总与可视化管理。平台涵盖人员、设备、物料、环境等关键因素的实时监控与数据分析,提供远程指挥、决策支持等功能,提升工作效率,促进产业信息化发展。系统由PC端、APP移动端及项目、监管、数据屏三大平台组成,支持微服务架构,采用Java、Spring Cloud、Vue等技术开发。
535 7