概述
@Import是Spring框架提供的一个注解,用于将实例加入到Spring的IOC容器中,提供类似@Bean注解的功能,也同效于Spring XML中的</import>,@Import有三种用法:
- 普通方式
- ImportSelector方式
- ImportBeanDefinitionRegister方式
@Import源码
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
@Target表示作用范围,可在类、接口、枚举上使用
value是仅有的属性,是一个类对象数组,数组值为交由IOC管理的对象
@Import的三种用法
1.普通方式
直接填写class,可以写入多个class
先创建一个普通类
package com.ck.springautomatic.test;
public class TestOne {
public void testPrintln(){
System.out.println("普通方式,直接写入class!");
}
}
然后利用Spring的ApplicationRunner来做测试
/**
* 服务启动后立即执行
* @author CK
*/
@Component
@Import(com.ck.springautomatic.test.TestOne.class)
public class StartRun implements ApplicationRunner {
@Autowired
private TestOne testOne;
@Override
public void run(ApplicationArguments args) throws Exception {
/** 获取IOC容器管理的实例 */
ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
String [] strings = applicationContext.getBeanDefinitionNames();
for(String str : strings){
/** 实例列表中是否包含@Import中加入的类 ,如包含打印True */
if(str.equals("com.ck.springautomatic.test.TestOne")){
System.out.println(Boolean.TRUE);
}
}
testOne.testPrintln();
}
}
运行后打印如下结果:
结论:TestOne实例成功的加入到IOC容器中,并且可以通过@Autowired注解来注入实例。
2.ImportSelector方式
加入的类需要实现实现ImportSelector接口
还是选用TestOne来做加入IOC的实例
先来看看ImportSelector接口的定义
public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}
- selectImport方法
返回一个包含类全名(包括包路径)的数组,这些类会注入到IOC容器中,必须实现
- getExclusionFilter方法
返回一个谓词,用于从导入候选对象中排除类,该谓词可作用于当前选择器中的所有类
创建一个MySelector类,实现ImportSelector接口及其selectImport方法
public class MySelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.ck.springautomatic.test.TestOne"};
}
}
还是使用Spring的ApplicationRunner来做测试,对@import做了改动
@Component
@Import(MySelector.class)
public class StartRun implements ApplicationRunner {
@Autowired
private TestOne testOne;
@Override
public void run(ApplicationArguments args) throws Exception {
/** 获取IOC容器管理的实例 */
ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
String [] strings = applicationContext.getBeanDefinitionNames();
for(String str : strings){
/** 实例列表中是否包含@Import中加入的类 ,如包含打印True */
if(str.equals("com.ck.springautomatic.test.TestOne")){
System.out.println(Boolean.TRUE);
}
}
testOne.testPrintln();
}
}
运行后打印如下结果:
结论:TestOne实例通过SelectorImport成功的加入到IOC容器中,并且可以通过@Autowired注解来注入实例。
思路扩展
自己实现@Enable***注解来加载所需的类
1.创建两个注解EnableOneA和EnableOneB,使用@Import注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MySelector.class)
public @interface EnableOneA {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(MySelector.class)
public @interface EnableOneB {
}
2.创建一个One接口,定义一个println(),OneA和OneB实现One接口并对println()进行不同的实现
public interface One {
void println();
}
public class OneA implements One {
@Override
public void println() {
System.out.println("装配的A!");
}
}
public class OneB implements One {
@Override
public void println() {
System.out.println("装配的B!");
}
}
3.Myselector中增根据注解加载对应的实现类到IOC容器
public class MySelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> list = new ArrayList<>();
Set<String> types = importingClassMetadata.getAnnotationTypes();
if(types.contains(EnableOneA.class.getName())){
list.add(OneA.class.getName());
}
if(types.contains(EnableOneB.class.getName())){
list.add(OneB.class.getName());
}
return list.toArray(new String[list.size()]);
}
}
4.在启动类上使用自定义注解@EnableOneA
@SpringBootApplication
@EnableOneA
public class SpringAutomaticApplication {
public static void main(String[] args) {
SpringApplication.run(SpringAutomaticApplication.class, args);
}
}
5.还是用Spring的ApplicationRunner来做测试,期望执行的是OneA中的实现
@Component
public class StartRun implements ApplicationRunner {
@Autowired
private One one;
@Override
public void run(ApplicationArguments args) throws Exception {
/** 获取IOC容器管理的实例 */
ApplicationContext applicationContext = ApplicationContextUtil.getApplicationContext();
String [] strings = applicationContext.getBeanDefinitionNames();
for(String str : strings){
/** 实例列表中是否包含@Import中加入的类 ,如包含打印True */
if(str.equals("com.ck.springautomatic.test.TestOne")){
System.out.println(Boolean.TRUE);
}
}
one.println();
}
}
6.启动,看输出结果
结论:通过自定义注解结合ImportSelector,成功的获取到了期望的OneA实例,很多@Enable**注解都是通过@Import和ImportSelector来实现(@EnableAsync、@EnableScheduling)
3.registerBeanDefinitions方式
通过BeanDefinitionRegistry来完成动态注册,这里不做过多解释,可以参考Mybatis的Mapper代理