在Java中,@Import
注解是用于引入其他配置类或Bean的注解。它可以帮助将特定的配置类或Bean注册到Spring容器中,使其可供应用程序使用。
@Import详解
@Import
注解可以用在@Configuration注解的类上,也可以用在普通的类上。它作为一个元注解,可以标记其他注解,例如@ImportResource
、@ImportSelector
和@ImportBeanDefinitionRegistrar
等。
使用@Import
注解,可以将以下内容导入到Spring容器中:
- 配置类(Configuration Class):通过导入其他的配置类,可以将其内部定义的Bean注册到容器中。
- 普通类(Non-configuration Class):将普通的类作为Bean导入到Spring容器中。
@Import源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {/*** {@link Configuration @Configuration}, {@link ImportSelector},* {@link ImportBeanDefinitionRegistrar}, or regular component classes to import.*/Class<?>[] value();}
从注释来看,@Import注解只可以标注在类上,可以结合 @Configuration注解、ImportSelector、ImportBeanDefinitionRegistrar一起使用,也可以导入普通的类。
因此,@Import的使用方式有4种:直接导入类,导入配置类来导入Bean,导入 ImportSelector 的实现类,导入 ImportBeanDefinitionRegister 的实现类。需要注意的是:ImportSelector、ImportBeanDefinitionRegistrar 这两个接口都必须依赖于 @Import 一起使用,而 @Import 可以单独使用。
@Import的实现原理
@Import
注解的实现原理涉及到Spring框架的组件扫描、Bean注册和依赖注入等机制
-
组件扫描:Spring框架会通过组件扫描机制,自动扫描并加载带有
@Configuration
注解或其他指定注解的配置类,将它们识别为配置类。 -
注册配置类:当一个配置类被识别后,Spring会将其实例化为一个Bean,并将其注册到容器中。这样,配置类内部定义的所有Bean都可以由Spring容器进行管理。
-
处理
@Import
注解:当在配置类上使用@Import
注解时,Spring会解析注解的参数,根据参数的不同类型进行相应的处理。-
导入其他配置类:如果
@Import
的参数是其他配置类(例如@Configuration
注解的类),Spring会将导入的配置类也加入到容器中,使得被导入的配置类内部定义的Bean也可以被管理。 -
导入普通类:如果
@Import
的参数是普通类,则Spring会将该类实例化为一个Bean,并注册到容器中。 -
导入实现了
ImportSelector
的类:如果@Import
的参数是实现了ImportSelector
接口的类,Spring会调用ImportSelector
接口的selectImports()
方法,根据返回的类名数组将相应的类注册为Bean。这样,可以根据特定的逻辑动态选择需要导入的类。 -
导入实现了
ImportBeanDefinitionRegistrar
的类:如果@Import
的参数是实现了ImportBeanDefinitionRegistrar
接口的类,Spring会调用ImportBeanDefinitionRegistrar
接口的registerBeanDefinitions()
方法,通过编程方式注册Bean定义到容器中。这样,可以通过自定义的逻辑来注册额外的Bean。
-
通过以上步骤,@Import
注解使得我们能够方便地导入其他配置类、普通类或实现了ImportSelector
、ImportBeanDefinitionRegistrar
接口的类,并将它们注册到Spring容器中,从而实现Bean的管理和依赖注入。
需要导入的类
public class HelloImport {public void test() {System.out.println("hello JF");}
}
1、直接导入类
@Import(HelloImport.class)
public class SpringTestApplication {public static void main(String[] args) {//1.通过AnnotationConfigApplicationContext创建spring容器,参数为@Import标注的类ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringTestApplication.class);HelloImport helloImport = applicationContext.getBean(HelloImport.class);elloImport.test();}
}
项目中常用以下方式:
@Import(HelloImport.class)
@Configuration
public class ConfigTest {
}
2、导入配置类注入Bean
@Configuration
public class HelloImportConfiguration {@Beanpublic HelloImport helloImport() {return new HelloImport();}
}@Import(HelloImportConfiguration.class)
public class SpringTestApplication {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringTestApplication.class);HelloImport helloImport = applicationContext.getBean(HelloImport.class);helloImport.test();}
}
这种方式的使用场景是配置类无法被直接扫描到。
3、导入 ImportSelector 实现类
ImportSelector是一个接口,实现这个接口需要重写selectImports方法。selectImports方法会返回一个String数组,它包含的元素是需要被导入到容器中的类的全限定名。
public class HelloImportSelector implements ImportSelector {/*** 返回需要导入的类名的数组,可以是任何普通类,配置类(@Configuration、@Bean、@CompontentScan等标注的类)* @importingClassMetadata:用来获取被@Import标注的类上面所有的注解信息*/@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {List list = new ArrayList<>();list.add("intl.skw.test.HelloImport");return StringUtils.toStringArray(list);}
}@Import(HelloImportSelector.class)
public class SpringTestApplication {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringTestApplication.class);HelloImport helloImport = applicationContext.getBean(HelloImport.class);helloImport.test();}
}
4、导入 ImportBeanDefinitionRegistrar 实现类
当类实现了 ImportBeanDefinitionRegistrar 接口,就可以拿到注册器,可以向容器中注册任何的Bean,并且可以对Bean添加属性。
public class HelloImportDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(HelloImport.class).getBeanDefinition();registry.registerBeanDefinition("HelloImport", beanDefinition);}
}@Import(HelloImportDefinitionRegistrar.class)
public class SpringTestApplication {public static void main(String[] args) {ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringTestApplication.class);HelloImport helloImport = applicationContext.getBean(HelloImport.class);helloImport.test();}
}