Skip to content

Import 注解的4种方式

根据该类的不同类型,Spring 容器针对 @Import 注解有以下四种处理方式:

1、如果该类实现了 ImportSelector 接口,Spring 容器就会实例化该类,并且调用其 selectImports 方法;

2、如果该类实现了 DeferredImportSelector 接口,则 Spring 容器也会实例化该类并调用其 selectImports方法。DeferredImportSelector 继承了 ImportSelector,区别在于 DeferredImportSelector 实例的 selectImports 方法调用时机晚于 ImportSelector 的实例,要等到 @Configuration 注解中相关的业务全部都处理完了才会调用;

3、如果该类实现了 ImportBeanDefinitionRegistrar 接口,Spring 容器就会实例化该类,并且调用其 registerBeanDefinitions 方法;

4、如果该类没有实现上述三种接口中的任何一个,Spring 容器就会直接实例化该类。

AutoConfigurationPackages.Registrar.class就实现了第三种情况,即实现了 ImportBeanDefinitionRegistrar 接口,Spring 容器启动时就会实例化该类,并且会调用其 registerBeanDefinitions 方法;

java
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new PackageImports(metadata));
        }
    }

AutoConfigurationPackages.register方法如下

java
 public static void register(BeanDefinitionRegistry registry, String... packageNames) {
        if (registry.containsBeanDefinition(BEAN)) {
            BasePackagesBeanDefinition beanDefinition = (BasePackagesBeanDefinition)registry.getBeanDefinition(BEAN);
            beanDefinition.addBasePackages(packageNames);
        } else {
            registry.registerBeanDefinition(BEAN, new BasePackagesBeanDefinition(packageNames));
        }

    }

该方法的逻辑是

1、先判断整个 Bean 有没有被注册,如果已经注册则获取 Bean 的定义,通过 Bean 获取构造函数的参数并添加参数值;

2、如果没有,则创建一个新的 Bean 的定义,设置 Bean 的类型为 AutoConfigurationPackages 类型并进行 Bean 的注册。