@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,应用正常执行.