Spring中使用@Import注册一个配置类时,这个配置类不应该再使用@Component或者@Configuration注解

    技术2025-10-03  7

    @Import注解参数三种类型

    普通Bean类型

    被导入的类会被注册成Spring容器中的一个Bean,可以被依赖注入使用,beanName为全类名。

    ImportSelector类型

    ImportSelector实现类不会被注册为Spring容器的一个Bean,但是其接口方法返回的全类名会被注册成bean,并且beanName为全类名

    //MyImportSelector不会被注册为bean public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { //ImportedBean1被注册为bean,并且beanName为全类名 return new String[]{ImportedBean1.class.getName()}; } }

    ImportBeanDefinitionRegistrar类型

    ImportBeanDefinitionRegistrar实现类不会被注册为bean,但是会回调其接口方法,由开发者通过Spring api手动向Spring容器注册bean

    public MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry){ //可以通过registry向Spring容器注册bean } }

    @Import注册一个配置类时,这个配置类不应该被@Component或者@Configuration注解标记。

    Spring中会将所有的bean class封装成一个ConfigurationClass,并且此后会解析这些配置类,该类中会有一个boolean类型返回值方法boolean ConfigurationClass#isImported,用于判断被封装的bean class是否是由其他类导入的。方法注释如下:

    Return whether this configuration class was registered via @Import or automatically registered due to being nested within another configuration class.

    中文解释:如果是通过@Import注册的类或者在配置类中定义的内部类会返回true,这里理解是否由其他类导入的。 如下示例:

    //其他代码省略.... @Import(B.class) @ConditionOnBean(C.class) //条件验证bean C是否存在 class A{ //只有当A上的条件验证通过时才会向Spring容器注入D @Bean public D d(){ return new D(); } }

    示例中B就是由A导入的一个Bean

    当被导入的类B在被实例化时,Spring会先验证导入B的A类上的条件注解是否验证通过,如果通过才会实例化B。而条件验证注解的结果同时会被缓存。

    而@Component或者@Configuration注解会让被@Import导入的类B,在Spring执行包扫描时被扫描到,此时不会被认为是由类A导入的。假如此时实例化Bean B,但是B依赖了A中定义的bean D,但是A此时的条件验证是不通过的,则会导致bean B创建时无法依赖bean D,最后抛出异常。

    如果类B正常由类A导入,没有被@Component或者@Configuration注解,那么在bean B实例化之前,会先验证类A上的条件注解是否通过,如果通过,那么类B在实例化过程中所依赖A中定义的bean D时也能够正常被创建,并被B所有依赖注入。如果不通过,则不会创建bean B,此时也不会查找从Spring容器中查找A中所定义的bean D,应用正常执行.

    Processed: 0.008, SQL: 9