• 解析@Import底层原理


    目录

    一、概述

     二、底层解析

    1、ConfigurationClassPostProcessor

    2、ConfigurationClassParser

     3、doProcessConfigurationClass

     4、processImports

    4.1 ImportSelector

     4.2 ImportBeanDefinitionRegistrar

      4.3 普通组件类

     三、测试类


    一、概述

    @Import用来向ioc容器注册组件。

    注意:@Import只是向容器注册添加组件的相关信息,组件还未实例化,后续由容器进行实例化。

    value数组值:

    普通组件类、实现ImportSelector接口的实现类、实现ImportBeanDefinitionRegistrar接口的实现类

    1、普通组件类:直接向容器注册组件,组件的id为组件的全限定类名,若是组件是一个配置类,则配置类内的组件(若配置类定义了内部类,也会扫描内部类判断是否加载该内部类)也会被注册到容器中

    2、实现ImportSelector接口的实现类:通过实现selectImports方法返回组件的全限定类名数组,组件的id为组件的全限定类名

    1. public class MyImportSelector implements ImportSelector {
    2. /**
    3. *
    4. * @param importingClassMetadata 当前标识Import注解的类的所有注解信息
    5. * @return 返回组件的全类名
    6. */
    7. @Override
    8. public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    9. return new String[]{"com.mzp.component.service.Red"};
    10. }
    11. }

    3、实现ImportBeanDefinitionRegistrar接口的实现类:通过实现registerBeanDefinitions方法,可自定义向容器注册组件,可指定组件id

    1. public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    2. /**
    3. *
    4. * @param importingClassMetadata 标识Import注解的类的所有注解信息
    5. * @param registry Bean定义的注册类
    6. */
    7. @Override
    8. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    9. RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainRow.class);
    10. registry.registerBeanDefinition("rain",rootBeanDefinition);
    11. }
    12. }

     二、底层解析

    1、ConfigurationClassPostProcessor

    用来解析标识@Configuration配置类。

    创建ioc容器时将ConfigurationClassPostProcessor注册到容器中,这是一个BeanDefinitionRegistryPostProcessor实现类,refresh方法中运行invokeBeanDefinitionRegistryPostProcessors方法时,调用ConfigurationClassPostProcessorpostProcessBeanDefinitionRegistry方法里的processConfigBeanDefinitions方法去解析容器已注册的标识@Configuration的配置类

     processConfigBeanDefinitions方法创建ConfigurationClassParser对象去解析@Configuration配置类的信息,包括解析注解@Import信息

    2、ConfigurationClassParser

    parse方法中调用processConfigurationClass方法

     processConfigurationClass方法通过循环调用doProcessConfigurationClass方法来解析当前配置类和配置类的父类信息

     3、doProcessConfigurationClass

    doProcessConfigurationClass方法解析多个spring注解,例如

    @PropertySource、@ComponentScan、@Import、@ImportResource、@Bean、解析内部类信息等

    解析内部类

     定位到如图processImports方法,该方法就是实际用来解析@Import注解

     getImports方法返回所有@Import注解的value集合,getImports方法通过collectImports方法获取当前组件标识@Import的value集合,包括元注解内部的@Import的value集合

     4、processImports

    processImports方法中遍历已得到@Import的value集合importCandidates,判断每个value属于哪种类型

    4.1 ImportSelector

    若是value实现了ImportSelector接口,则先通过容器工具类创建对象,然后调用对象的selectImports方法得到导入组件数组importClassNames,继续递归调用processImports方法解析每个导入组件

     4.2 ImportBeanDefinitionRegistrar

    若是value实现了ImportBeanDefinitionRegistrar接口, 创建该对象,将对象添加到当前类的importBeanDefinitionRegistrars集合中

     在后续解析完所有的@Configuration配置类后,调用ConfigurationClassPostProcessorloadBeanDefinitions方法注册每个配置组件类到容器时,

     调用loadBeanDefinitionsForConfigurationClass方法loadBeanDefinitionsFromRegistrars方法运行当前类的importBeanDefinitionRegistrars集合的registerBeanDefinitions方法

      4.3 普通组件类

    当前value都没实现ImportSelectorImportBeanDefinitionRegistrar接口时,将它当成一个配置类继续调用processConfigurationClass方法解析该配置类

     三、测试类

    1. @Test
    2. public void test15(){
    3. ApplicationContext applicationContext = new AnnotationConfigApplicationContext(ImportConfig.class);
    4. }
    1. package com.mzp.component.myimport;
    2. import com.mzp.component.service.RainRow;
    3. import org.springframework.beans.factory.support.BeanDefinitionRegistry;
    4. import org.springframework.beans.factory.support.RootBeanDefinition;
    5. import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
    6. import org.springframework.core.type.AnnotationMetadata;
    7. public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    8. /**
    9. *
    10. * @param importingClassMetadata 标识Import注解的类的所有注解信息
    11. * @param registry Bean定义的注册类
    12. */
    13. @Override
    14. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    15. RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(RainRow.class);
    16. registry.registerBeanDefinition("rain",rootBeanDefinition);
    17. }
    18. }
    1. package com.mzp.component.myimport;
    2. import org.springframework.context.annotation.ImportSelector;
    3. import org.springframework.core.type.AnnotationMetadata;
    4. public class MyImportSelector implements ImportSelector {
    5. /**
    6. *
    7. * @param importingClassMetadata 当前标识Import注解的类的所有注解信息
    8. * @return 返回组件的全类名
    9. */
    10. @Override
    11. public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    12. return new String[]{"com.mzp.component.service.Red"};
    13. }
    14. }
    1. package com.mzp.component.myimport;
    2. public class Test {
    3. public Test(){
    4. System.out.println("Test()");
    5. }
    6. }
    1. package com.mzp.component.config;
    2. import com.mzp.component.myimport.MyImportBeanDefinitionRegistrar;
    3. import com.mzp.component.myimport.MyImportSelector;
    4. import com.mzp.component.myimport.Test;
    5. import org.springframework.context.annotation.Configuration;
    6. import org.springframework.context.annotation.Import;
    7. @Configuration
    8. @Import(value = {Test.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
    9. public class ImportConfig {
    10. }

  • 相关阅读:
    聚观早报 | 东方甄选推出独立 App;腾讯《冒险岛 2》即将停服
    【数据结构初阶】四、线性表里的链表(带头+双向+循环 链表)
    分布式医疗大数据存储方案研究综述
    案例分享 | 机场急救中心项目中BIM应用
    【JavaWeb】 一文搞懂Request
    sklearn机器学习——day13
    数据文件采用错误方式删除后的解决办法
    vue3源码的下载与安装
    旺店通企业版与金蝶云星辰数据集成方案分享
    01-java入门了解--cmd命令、jdk、java的认识
  • 原文地址:https://blog.csdn.net/weixin_37607613/article/details/126179029