ConfigurationClassPostProcessor详解
本篇主要详细说明ConfigurationClassPostProcessor。
目前都是通过纯注解的方式使用Spring框架,虽然侵入性很强,但是能减少开发人员的工作量。基于注解的方式用的是AnnotationConfigApplicationContext上下文对象。
一、核心流程的入口
进入this,来到AnnotatedBeanDefinitionReader,可以看到registerAnnotationConfigProcessors中注册了ConfigurationClassPostProcessor。
ConfigurationClassPostProcessor的核心逻辑在postProcessBeanDefinitionRegistry的processConfigBeanDefinitions中,由此可知processConfigBeanDefinitions是bean在实例化前调用的(postProcessBeanDefinitionRegistry在bean实例化之前执行,具体可以看这篇 Spring在Bean实例化前的操作)。
获取所有的beanName,看BeanDefinition中是否有处理完成的标识。没有处理完成的标识则在checkConfigurationClassCandidate中判断是否是候选的需要处理的BeanDefinition,如果是就放入容器configCandidates。
首先判断BeanDefinition是扫描注解产生的还是自己添加的,拿到metadata对象,metadata中包含了类的注解信息。
根据metadata中的注解判断是full匹配还是lite匹配。
创建解析器、需要解析的BeanDefinitionHolder容器和已经解析过的BeanDefinition容器。
在parse中可以看到具体的解析过程。基于注解的BeanDefinition一般是AnnotatedBeanDefinition的实现类ScannedGenericBeanDefinition,手动添加的BeanDefinition一般是AbstractBeanDefinition的子类GenericBeanDefinition和RootBeanDefinition。ScannedGenericBeanDefinition又是GenericBeanDefinition的子类,于是就有了下面这个解析顺序。
扫描注解的parse方法中,先把metadata和beanName包装成ConfigurationClass对象,在processConfigurationClass中再把ConfigurationClass和filter包装成SourceClass。
二、注解的收集
进入doProcessConfigurationClass,判断类上面是否有Component注解,递归处理有候选注解的内部类,把父类放到importedBy容器中。
处理PropertySources和 PropertySource注解,创建PropertySource对象加入到Environment对象中。
处理ComponentScans和ComponentScan注解,扫描到@Component生成beanDefinition后,还要递归去校验类上面是否有其他特殊注解,也是通过ConfigurationClassParser.processConfigurationClass处理。
下面是处理@Import注解的流程。getImports中收集@Import注解和注解中的值。
三、ImportSelector接口和DeferredImportSelector接口和ImportBeanDefinitionRegistrar接口
在processImports中循环处理@Import注解。这里会处理ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar接口。因此,某个类实现ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar接口后,只有被@Import,对应的接口方法才会被处理,加上@Component注解反而不会被处理。实现这3类接口的类都不会被加入Spring容器。
处理ImportSelector接口时,会调用selectImports方法,方法的返回值是要加入到spring容器的类全限定名,方便拿到metaData对象。selectImports的方法参数是当前有@Import注解的类的AnnotationMetadata对象,也就是说在实现了ImportSelector接口的selectImports方法中可以拿到有@Impor