您的当前位置:首页正文

@Configuration注解的类的加载(注意不是处理@Configuration注解处理)实现原理

2024-11-12 来源:个人技术集锦

概述

  • 这里主要分析@Configuration注解的类自身的加载的实现,即生成该类对应的BeanDefinition,注册到BeanFactory,此时该类就跟一个普通使用了如@Component注解的类一样,是在创建和初始化BeanFactory的过程中完成的。而@Configuration注解的处理是通过ConfigurationClassPostProcessor来完成的,ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor接口实现类。
  • 以下先从我们熟悉的@Configuration注解的处理实现说起,然后再回过头来分析在执行@Configuration的注解处理之前,@Configuration注解的类是怎么注册到BeanFactory中的。通俗来说,就以先分析怎么煎鸡蛋,再分析这个鸡蛋怎么被母鸡生出来的思路来分析。

@Configuration的注解处理器ConfigurationClassPostProcessor的创建

  • AnnotationConfigBeanDefinitionParser是<context:annotation-config />的标签处理器。
  • AnnotationConfigBeanDefinitionParser会调用AnnotationConfigUtils.registerAnnotationConfigProcessors方法;
  • 如果Spring容器所使用的ApplicationContext接口实现类为AnnotationConfigApplicationContext,则也会调用这个方法。
  • AnnotationConfigUtils.registerAnnotationConfigProcessors方法的执行,会注册三个注解处理器,分别是:

@Configuration注解的类的加载

  • ConfigurationClassPostProcessor为BeanFactoryPostProcessor,此时是从BeanFactory获取已经创建好的BeanDefinition,检测每个BeanDefinition对应的类上面是否使用了以上四个注解。所以在基于注解的配置设计中,对应的类怎么才能生成对应的BeanDefinition注册到BeanFactory,之后才能被ConfigurationClassPostProcessor处理?如果是基于XML的,一般会在applicationContext.xml中通过<context:component-scan />注解或者bean标签,获取到了相关的BeanDefinition。
  • 其实@Configuration注解的作用是作为一个配置类,对应类内部使用@Bean注解方法,则该方法会作为BeanDefinition注册到BeanFactory中。以及扫描一起使用的@ComponentScan注解指定的类或包,获取对应的BeanDefinition。

Spring容器ApplicationContext

  • 但是对于Spring容器而言,即ApplicationContext接口的实现类,既可以是基于XML的XmlApplicationContext,即使用applicationContext.xml来作为配置,也可以是基于JavaConfig,如实现WebApplicationInitializer接口,在这个接口的onStartup方法中,指定特定的ApplicationContext,一般为AnnotationConfigApplicationContext,并指定使用了@Configuration注解的配置类,作为AnnotationConfigApplicationContext的构造函数参数值。所以针对这两种方式,分别说明如何使@Configuration注解的类,先作为BeanDefinition注册到BeanFactory,然后再被ConfigurationClassPostProcessor处理其上的注解。
    1. 基于applicationContext.xml:使用<context:component-scan />标签,并在base-package属性指定的@Configuration类所在的包,则Spring容器启动时,就会加载@Configuration注解类并创建BeanDefinition对象注册到BeanFactory中,之后ConfigurationClassPostProcessor作为BeanFactoryPostProcessor,从BeanFactory取出并赛选使用了@Configuration注解的类对应的的BeanDefinition,处理其上的@ComponentScan等注解和类内部使用@Bean注解的方法。

    2. 基于JavaConfig的方式,在WebApplicationInitializer接口实现类的onStartup方法中,以@Configuration注解的类作为构造函数参数,创建AnnotationConfigApplicationContext对象,然后交给该对象以attribute方式添加到ServletContext中。此时AnnotationConfigApplicationContext在内部会使用AnnotatedBeanDefinitionReader注册这个使用了@Configuration注解的配置类到BeanFactory中。之后ConfigurationClassPostProcessor完成与基于applicationContext.xml的方式中一样的处理。

    3. SpringBoot的处理方式:SpringBoot的SpringApplication使用AnnotationConfigApplicationContext作为Spring容器的ApplicationContext,然后将main方法所在启动类作为参数调用SpringApplication.run方法,其中该启动类为一个基于注解的配置类,一般为@SpringBootApplication注解或者@Configuration注解等。SpringApplication初始化启动时,与基于JavaConfig的方式一样,也是通过AnnotatedBeanDefinitionReader来将启动类作为BeanDefinition注册到BeanFactory的,之后使用ConfigurationClassPostProcessor来处理相关注解。

 

显示全文