@Import这个注解非常重要,而且在springboot项目当中随处可见,就拿springboot启动类来说,我们经常会遇到一些@Enable相关的注解,例如开启异步@EnableAsync、开启缓存支持@EnableCaching、开启定时任务@EnableScheduling等等…
点开源码会发现他没有使用其他特别的注解,就是用了三个元注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {Class>[] value();
}
这些@Enable注解你点进去就发现都是使用的@Import注解,就是利用@Import注解来将指定的配置类加载到容器当中!

@Import属于spring当中的注解,在spring-context包下。@Import源码,以及官网解释该注解:https://github.com/spring-projects/spring-framework/blob/main/spring-context/src/main/java/org/springframework/context/annotation/Import.java
(1)源码注释比较清楚地说明了@Import注解的作用,这里我翻译一下:
元素的功能,允许导入@Configuration类、ImportSelector的实现和ImportBeanDefinitionRegistrar的实现,当然也可以导入一个常规的类作为Component(类似于4.2版本后,利用AnnotationConfigApplicationContext类的register方法导入一个普通的类作为Component)@ImportResource注解代替@Import注解,去导入xml配置(2)根据上面的翻译,我总结一下@Import注解的用法
@Import必须要在@controller、@Service、@Component、@Configuration、@Repository修饰的类下,并且要在springboot扫描范围内,这些注解修饰的类默认是必须和springboot启动类同包才会被扫描到,当然也可以手动指定扫描包。在启动类上使用@Import也是可以的!使用@Bean注解间接创建的对象当中使用@Import是不可以的。如下示例就是不可以的哦!@Configuration
public class Myconfig {@Beanpublic MyconfigTest myconfigTest(){return new MyconfigTest();}
}@Import({TestBean1.class})
public class MyconfigTest {
}
(3)这些用法或许只有一个目的,就是导入Bean。那为什么要这么麻烦,手动导入Bean呢,@ComponentScan不是可以自动扫描包注册Bean嘛?其实这里的原因有两点:
(4)@Import等同于之前的标签
官方解释:
元素在Spring XML文件中用于帮助模块化配置一样,@Import注释允许从另一个配置类加载@Bean定义,如果您想要避免组件扫描,通过使用一些配置类作为入口点显式定义所有组件,Import尤其有用。
通过@Import注入对象的四种方式
理论我们都明白了,剩下来实操,首先定义四个类,我们分别用不同的方式将这四个类存到容器当中。
public class TestBean1 {@Overridepublic String toString() {return super.toString() + "--我是TestBean1";}
}public class TestBean2 {@Overridepublic String toString() {return super.toString() + "--我是TestBean2";}
}public class TestBean3 {@Overridepublic String toString() {return super.toString() + "--我是TestBean3";}
}public class TestBean4 {@Overridepublic String toString() {return super.toString() + "--我是TestBean4";}
}
方式一:间接的@Configuration和@Bean注入
注意:ImportBeanByConfig类不能被@ComponentScan扫描到,如果扫描到通过@Configuration注解都可以将testBean2放入到容器当中了,用@Import注解导入它就没有意义了
@Configuration
public class ImportBeanByConfig {@Beanpublic TestBean2 testBean2(){return new TestBean2();}
}
方式二:创建ImportSelector实现
ImportSelector接口只定义了一个String[] selectImports(AnnotationMetadata importingClassMetadata);,用于指定需要注册为bean的Class名称。使用@Import引入了一个ImportSelector实现类后,会把实现类中返回的Class名称都定义为bean。
public class ImportBeanByImportSelector implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {// 这里全类名return new String[]{"com.gzl.cn.springbootcache.config.TestBean3"};}
}
方式三:创建ImportBeanDefinitionRegistrar实现
public class ImportBeanByImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(TestBean4.class);registry.registerBeanDefinition("TestBean4", rootBeanDefinition);}
}
方式四:直接被注入(直接写要注入的类class)
ImportTest类是需要被@ComonentScan扫到的,否则@Import直接不会生效
@Import({TestBean1.class,ImportBeanByConfig.class,ImportBeanByImportSelector.class,ImportBeanByImportBeanDefinitionRegistrar.class})
@Configuration
public class ImportTest {
}
写一个Controller方法测试
正常使用@Autowired注解的话,假如容器当中没有这个对象是会报错的,所以我们这里设置为
required = false,这样就算没有这个对象,启动不会报错。
@RestController
public class CommonController {@Autowired(required = false)private TestBean1 testBean1;@Autowired(required = false)private TestBean2 testBean2;@Autowired(required = false)private TestBean3 testBean3;@Autowired(required = false)private TestBean4 testBean4;@RequestMapping("/import")public void printImportBeanInfo() {System.out.println(testBean1);System.out.println(testBean2);System.out.println(testBean3);System.out.println(testBean4);}
}
测试结果:

将ImportTest类的@Import注释掉,再次访问HTTP接口,控制台打印日志如下:

@ImportAutoConfiguration和@EnableAutoConfiguration就是通过@Import注解所扩展出来的注解,@ImportAutoConfiguration应该用到的比较少,但是@EnableAutoConfiguration注解大家应该不陌生吧,他是springboot当中@SpringBootApplication启动注解当中的组合注解之一,读springboot源码基本上都需要了解这个的。

早在以前我们注入bean都是 通过xml来实现的,springboot项目当中已经很少见了,都是通过注解来存放到容器当中的,@ImportResource就是将xml配置文件生效。接下来通过代码来演示他的作用。
(1)创建一个类
@Data
public class Student {private String name;private Integer age;
}
(2)添加applicationContext.xml

(3)添加配置
@Configuration
@ImportResource(locations = "classpath:applicationContext.xml")
public class Myconfig {
}
(4)添加测试
@RestController
public class CommonController {@Autowired(required = false)private Student student;@RequestMapping("/import")public void printImportBeanInfo() {System.out.println(student);}
}
(5)启动访问接口:打印如下,成功从容器当中取出。

假如把@ImportResource(locations = "classpath:applicationContext.xml")去掉打印如下:
