0


@Import注解详解

@Import注解提供了三种用法

1、@Import一个普通类 spring会将该类加载到spring容器中

2、@Import一个类,该类实现了ImportBeanDefinitionRegistrar接口,在重写的registerBeanDefinitions方法里面,能拿到BeanDefinitionRegistry bd的注册器,能手工往beanDefinitionMap中注册 beanDefinition

3、@Import一个类 该类实现了ImportSelector 重写selectImports方法该方法返回了String[]数组的对象,数组里面的类都会注入到spring容器当中

接下来挨个测试:

场景一 import普通类

  1. 自定义一个类 没有任何注解
public class MyClass {
    
    public void test() {
        System.out.println("test方法");
    }
}
  1. 写一个importConfig类 import这个myClass类
@Import(MyClass.class)
public class ImportConfig {
    
}
  1. 通过AnnotationConfigApplicationContext 初始化spring容器 调用test方法 看输出, MyClass类被加载进了 spring容器当中

场景二、 实现ImportBeanDefinitionRegistrar

  1. 创建一个普通类MyClassRegistry
public class MyClassRegistry {
    
    public void test() {
        System.out.println("MyClassRegistry test方法");
    }
}
  1. 创建MyImportRegistry 实现ImportBeanDefinitionRegistrar接口 注册我们定义的普通类MyClassRegistry
public class MyImportRegistry implements ImportBeanDefinitionRegistrar{
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition bd = new RootBeanDefinition();
        bd.setBeanClass(MyClassRegistry.class);
        registry.registerBeanDefinition("myClassRegistry", bd);
    }
}
  1. import该类
@Import(MyImportRegistry.class)
public class ImportConfig {
    
}
  1. 执行main方法 查看输出

场景三、 实现ImportSelector

  1. 创建一个普通类MyClassImport
public class MyClassImport {
    
    public void test() {
        System.out.println("MyClassImport test方法");
    }
}
  1. 创建MyImportSelector实现ImportSelector接口 注册我们定义的普通类MyClassImport
public class MyImportSelector implements ImportSelector {

    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[] {MyClassImport.class.getName()};
    }

}
  1. import该类
@Import(MyImportSelector.class)
public class ImportConfig {
    
}
  1. 执行main方法 查看输出

场景二应用于spring-mybatis当中 扫描dao信息 生成代理类信息

场景三应用于springboot的自动装配当中 加载自动装配需要的类信息

源码分析:

org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClass, SourceClass, Collection<SourceClass>, boolean)方法中 就是处理Import注解类引入的bd信息

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
            Collection<SourceClass> importCandidates, boolean checkForCircularImports) {

        if (importCandidates.isEmpty()) {
            return;
        }

        if (checkForCircularImports && isChainedImportOnStack(configClass)) {
            this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
        }
        else {
            this.importStack.push(configClass);
            try {
                for (SourceClass candidate : importCandidates) {
                    if (candidate.isAssignable(ImportSelector.class)) {//拿ImportSelector类
                    
                        Class<?> candidateClass = candidate.loadClass();//获得class信息
                        ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                                this.environment, this.resourceLoader, this.registry);
                        if (selector instanceof DeferredImportSelector) {//判断是否是延迟加载的ImportSelector对象
                            this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
                        }
                        else {
                            String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());//拿到selectImports方法返回的类信息
                            Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
                            processImports(configClass, currentSourceClass, importSourceClasses, false);
                        }
                    }
                    else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {//扫描到类是继承ImportBeanDefinitionRegistrar 将配置类封装成ConfigurationClass类 后续会处理
                        // Candidate class is an ImportBeanDefinitionRegistrar ->
                        // delegate to it to register additional bean definitions
                        Class<?> candidateClass = candidate.loadClass();
                        ImportBeanDefinitionRegistrar registrar =
                                ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                        this.environment, this.resourceLoader, this.registry);
                        configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                    }
                    else {
                        // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                        // process it as an @Configuration class
                        this.importStack.registerImport(
                                currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                        processConfigurationClass(candidate.asConfigClass(configClass));
                    }
                }
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to process import candidates for configuration class [" +
                        configClass.getMetadata().getClassName() + "]", ex);
            }
            finally {
                this.importStack.pop();
            }
        }
    }

org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(Set<ConfigurationClass>)

在loadBeanDefinitions中会调用loadBeanDefinitionsFromRegistrars方法 最终执行到实现类的registerBeanDefinitions方法 继而将自定义的bd注册到beanDefinitionMap当中 交给spring去初始化

标签: spring java

本文转载自: https://blog.csdn.net/weixin_45453628/article/details/124234317
版权归原作者 中年危机的老男人 所有, 如有侵权,请联系我们删除。

“@Import注解详解”的评论:

还没有评论