• Spring-@Import介绍


    一、@Import作用总结

    //使用方式
    @Import(xxx.class)
    @Configuration
    public class AppConfigClassTest {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1、如果xxx.class这个类实现了ImportSelector,执行重写的方法selectImports, 该方法返回一个Class集合,并且这些Class集合会被注入到spring里面去。关于ImportSelector接口的使用和介绍请看这篇文章@ImportSelector注解

    2、如果xxx.class这个类实现了ImportBeanDefinitionRegistrar接口,执行重写ImportBeanDefinitionRegistrar接口里面BeanDefinitionRegistry方法,该方法经常用来往Spring注册Bean,关于ImportBeanDefinitionRegistrar可以看我这偏文章ImportBeanDefinitionRegistrar接口介绍

    3、否者就把这个xxx.class当成Bean注册到Spring里面去

    下面介绍下@Import源码是如何处理上面三种情况的。这里说明一下Spring处理@Import是在ConfigurationClassPostProcessor这个后置处理里面触发,spring为什么这么设计,ConfigurationClassPostProcessor这个后置处理器不是处理@Configuration注解的吗? 因为@Import的使用要和@Configuration组合一起使用,所以在解析带有@Configuration注解的类时,会同时解析该类上面是否包含@Import注解、是否包含@Bean注解的方法属性等。

    //这里就直接跳到ConfigurationClassPostProcessor处理@Import注解的逻辑上
    private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, 
                    Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) {
    
        //如果importCandidates为空直接return,为什么会有这个,因为下面代码可能会递归调用processImports,就比如Import一个类,这个类也带了@Import注解,那就会在调用一次processImports方法
        if (importCandidates.isEmpty()) {
            return;
        }
    
        for (SourceClass candidate : importCandidates) {
            if (candidate.isAssignable(ImportSelector.class)) {
            	//1、import的类,实现了ImportSelector接口
                Class<?> candidateClass = candidate.loadClass();
                //利用反射Class实例化对象,这个对象不是代理对象不要搞混了。
                ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                        this.environment, this.resourceLoader, this.registry);
                Predicate<String> selectorFilter = selector.getExclusionFilter();
                if (selectorFilter != null) {
                    exclusionFilter = exclusionFilter.or(selectorFilter);
                }
                if (selector instanceof DeferredImportSelector) {
                    this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                } else {
                	//调用ImportSelector接口里面的selectImports方法,拿到返回值Class集合。在通过递归的方式嗲用processImports挨个解析每一个Class
                    String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                    Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                    processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                }
            } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                //2、import的类实现了ImportBeanDefinitionRegistrar接口	
                Class<?> candidateClass = candidate.loadClass();
                //通过反射实例化ImportBeanDefinitionRegistrar的实现类,并添
                //加到Map中,这个Map里面存的都是ImportBeanDefinitionRegistrar实现类,后面会有其他处理统一处理。
                ImportBeanDefinitionRegistrar registrar =
                        ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                this.environment, this.resourceLoader, this.registry);
                                
                configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
            } else {
                //3、ImportSelector和ImportBeanDefinitionRegistrar都没有实现
                this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                //进一步解析其他注解,比如@Component @Import等最后会把configClass注册到Spring容器中。
                processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
  • 相关阅读:
    【Android入门】7、多媒体:用 NotificationChannel 和 NotificationManager 实现系统通知、播放音频和视频
    【CVPR 2018】PIXOR: 点云中三维目标的实时检测
    2.Asp.net Core使用Redis-StackExchange.Redis操作
    go实现自定义rpc框架 (核心:服务端&客户端、自定义io流、编解码、服务发现、负载均衡、支持多语言网关等)
    python flask框架接受axios发送的图片文件
    git仓库中增加子仓库
    分组后成员的再分组
    FAPROTAX分析:R语言实现微生物群落功能注释分析及可视化
    C#中通过LINQtoXML加载、创建、保存、遍历XML和修改XML树
    Vue2:官方路由 Vue-Router 3.x
  • 原文地址:https://blog.csdn.net/weixin_37862824/article/details/133080852