以下先从我们熟悉的@Configuration注解的处理实现说起,然后再回过头来分析在执行@Configuration的注解处理之前,@Configuration注解的类是怎么注册到BeanFactory中的。通俗来说,就以先分析怎么煎鸡蛋,再分析这个鸡蛋怎么被母鸡生出来的思路来分析。
Spring容器ApplicationContext
但是对于Spring容器而言,即ApplicationContext接口的实现类,既可以是基于XML的XmlApplicationContext,即使用applicationContext.xml来作为配置,也可以是基于JavaConfig,如实现WebApplicationInitializer接口,在这个接口的onStartup方法中,指定特定的ApplicationContext,一般为AnnotationConfigApplicationContext,并指定使用了@Configuration注解的配置类,作为AnnotationConfigApplicationContext的构造函数参数值。所以针对这两种方式,分别说明如何使@Configuration注解的类,先作为BeanDefinition注册到BeanFactory,然后再被ConfigurationClassPostProcessor处理其上的注解。基于applicationContext.xml:使用<context:component-scan />标签,并在base-package属性指定的@Configuration类所在的包,则Spring容器启动时,就会加载@Configuration注解类并创建BeanDefinition对象注册到BeanFactory中,之后ConfigurationClassPostProcessor作为BeanFactoryPostProcessor,从BeanFactory取出并赛选使用了@Configuration注解的类对应的的BeanDefinition,处理其上的@ComponentScan等注解和类内部使用@Bean注解的方法。
基于JavaConfig的方式,在WebApplicationInitializer接口实现类的onStartup方法中,以@Configuration注解的类作为构造函数参数,创建AnnotationConfigApplicationContext对象,然后交给该对象以attribute方式添加到ServletContext中。此时AnnotationConfigApplicationContext在内部会使用AnnotatedBeanDefinitionReader注册这个使用了@Configuration注解的配置类到BeanFactory中。之后ConfigurationClassPostProcessor完成与基于applicationContext.xml的方式中一样的处理。
SpringBoot的处理方式:SpringBoot的SpringApplication使用AnnotationConfigApplicationContext作为Spring容器的ApplicationContext,然后将main方法所在启动类作为参数调用SpringApplication.run方法,其中该启动类为一个基于注解的配置类,一般为@SpringBootApplication注解或者@Configuration注解等。SpringApplication初始化启动时,与基于JavaConfig的方式一样,也是通过AnnotatedBeanDefinitionReader来将启动类作为BeanDefinition注册到BeanFactory的,之后使用ConfigurationClassPostProcessor来处理相关注解。