@Import注解详解
创始人
2024-01-13 02:01:03

@Import这个注解非常重要,而且在springboot项目当中随处可见,就拿springboot启动类来说,我们经常会遇到一些@Enable相关的注解,例如开启异步@EnableAsync、开启缓存支持@EnableCaching、开启定时任务@EnableScheduling等等…

目录

    • 一、@Import源码
    • 二、@Import官网介绍
    • 三、@Import的四种用法
    • 四、@Import扩展注解
    • 五、@ImportResource注解

一、@Import源码

点开源码会发现他没有使用其他特别的注解,就是用了三个元注解:

  • @Target({ElementType.TYPE}): 使用范围接口、类、枚举、注解
  • @Retention(RetentionPolicy.RUNTIME): @Retention是用来修饰注解的生命周期的,RetentionPolicy.RUNTIME代表的是不仅被保存到class文件中,jvm加载class文件之后,仍然存在;一直有效!
  • @Documented: @Documented和@Deprecated注解长得有点像,@Deprecated是用来标注某个类或者方法不建议再继续使用,@Documented只能用在注解上,如果一个注解@B,被@Documented标注,那么被@B修饰的类,生成Javadoc文档时,会显示@B。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {Class[] value();
}

二、@Import官网介绍

这些@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注解的作用,这里我翻译一下:

  • 声明一个或多个Component(Component代表的是组件,或者可以理解为对象)
  • 提供等同于spring的xml配置中元素的功能,允许导入@Configuration类、ImportSelector的实现和ImportBeanDefinitionRegistrar的实现,当然也可以导入一个常规的类作为Component(类似于4.2版本后,利用AnnotationConfigApplicationContext类的register方法导入一个普通的类作为Component)
  • 在@Configuration中声明的Bean应该被@Autowired注解注入,可以自动连接bean本身,也可以自动连接声明bean的配置类实例,后者允许在@Configuration类的方法之间进行显式的、IDE友好的导航
  • 可以声明在类级别上,或者作为一个元注解
  • 可以用@ImportResource注解代替@Import注解,去导入xml配置

(2)根据上面的翻译,我总结一下@Import注解的用法

  • 作用:
    • 导入一个或多个Bean
    • 导入@Configuration类
    • 导入ImportSelector的实现类
    • 导入ImportBeanDefinitionRegistrar的实现类
  • 使用前提: @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嘛?其实这里的原因有两点:

  • @ComponentScan一般只会扫到自己项目中的Bean,第三方jar包中的@Bean扫不到
  • @Import注解可以结合@Conditional注解使用,即条件导入,@Conditional在spring源码中也是大量用到,这个我后面会专题介绍

(4)@Import等同于之前的标签

官方解释:元素在Spring XML文件中用于帮助模块化配置一样,@Import注释允许从另一个配置类加载@Bean定义,如果您想要避免组件扫描,通过使用一些配置类作为入口点显式定义所有组件,Import尤其有用。



三、@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接口,控制台打印日志如下:

在这里插入图片描述

四、@Import扩展注解

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

在这里插入图片描述

五、@ImportResource注解

早在以前我们注入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")去掉打印如下:

在这里插入图片描述

相关内容

热门资讯

demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...