当前位置: 首页 > news >正文

@Import注解详解

@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配置中<import/>元素的功能,允许导入@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 {
	@Bean
    public 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等同于之前的<import/>标签

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

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>

    <bean id="bean1" class="..."/>
    <bean id="bean2" class="..."/>
</beans>

三、@Import的四种用法

通过@Import注入对象的四种方式

理论我们都明白了,剩下来实操,首先定义四个类,我们分别用不同的方式将这四个类存到容器当中。

public class TestBean1 {
    @Override
    public String toString() {
        return super.toString() + "--我是TestBean1";
    }
}

public class TestBean2 {
    @Override
    public String toString() {
        return super.toString() + "--我是TestBean2";
    }
}

public class TestBean3 {
    @Override
    public String toString() {
        return super.toString() + "--我是TestBean3";
    }
}

public class TestBean4 {
    @Override
    public String toString() {
        return super.toString() + "--我是TestBean4";
    }
}

方式一:间接的@Configuration和@Bean注入

注意:ImportBeanByConfig类不能被@ComponentScan扫描到,如果扫描到通过@Configuration注解都可以将testBean2放入到容器当中了,用@Import注解导入它就没有意义了

@Configuration
public class ImportBeanByConfig {
    @Bean
    public TestBean2 testBean2(){
        return new TestBean2();
    }
}

方式二:创建ImportSelector实现

ImportSelector接口只定义了一个String[] selectImports(AnnotationMetadata importingClassMetadata);,用于指定需要注册为bean的Class名称。使用@Import引入了一个ImportSelector实现类后,会把实现类中返回的Class名称都定义为bean

public class ImportBeanByImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
    	// 这里全类名
        return new String[]{"com.gzl.cn.springbootcache.config.TestBean3"};
    }
}

方式三:创建ImportBeanDefinitionRegistrar实现

public class ImportBeanByImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public 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

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="dog1" class="com.gzl.cn.springbootcache.config.Student">
        <property name="name" value="zhangsan"/>
        <property name="age" value="27"/>
    </bean>
</beans>

(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")去掉打印如下:

在这里插入图片描述

相关文章:

  • 基于springboot+vue的美食分享网站
  • 动态规划-斐波拉契数列笔记
  • 农民工学CSAPP题目解析-前篇题目解答以及答疑总结
  • HBase系列从入门到精通(二)
  • libusb系列-002-Windows下libusb源码编译
  • 【C++ 科学计算】C++ 矩阵操作运算符
  • 全排列笔记
  • Python环境变量与引包错误
  • Mysql内置函数整理--基础类型函数
  • 万字爽文一篇带你掌握Java8新特性
  • Node.js的Web后端开发调研
  • Spring、MySQL、日期、BigDecimal、集合、反射、序列化中的坑与使用指南
  • DC 交换机 buffer 的平方反比律
  • 编程神器Copilot逐字抄袭他人代码?
  • 【数据结构】初始集合框架
  • 自己简单写的 事件订阅机制
  • Angular 2 DI - IoC DI - 1
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • Docker 笔记(2):Dockerfile
  • es6(二):字符串的扩展
  • Fabric架构演变之路
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • java正则表式的使用
  • Linux gpio口使用方法
  • NLPIR语义挖掘平台推动行业大数据应用服务
  • supervisor 永不挂掉的进程 安装以及使用
  • Vue ES6 Jade Scss Webpack Gulp
  • Vue.js源码(2):初探List Rendering
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 微信公众号开发小记——5.python微信红包
  • 微信小程序实战练习(仿五洲到家微信版)
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • #DBA杂记1
  • #LLM入门|Prompt#3.3_存储_Memory
  • #QT(串口助手-界面)
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (翻译)terry crowley: 写给程序员
  • (机器学习-深度学习快速入门)第三章机器学习-第二节:机器学习模型之线性回归
  • (论文阅读11/100)Fast R-CNN
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • (转)真正的中国天气api接口xml,json(求加精) ...
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .Net6使用WebSocket与前端进行通信
  • .NET成年了,然后呢?
  • .NET下的多线程编程—1-线程机制概述
  • .Net中wcf服务生成及调用
  • ?php echo ?,?php echo Hello world!;?
  • [20150707]外部表与rowid.txt
  • [android学习笔记]学习jni编程
  • [BZOJ 1032][JSOI2007]祖码Zuma(区间Dp)
  • [BZOJ1060][ZJOI2007]时态同步 树形dp
  • [C#]科学计数法(scientific notation)显示为正常数字