不是银趴~是@Import!
首先我们要明确:@Import 注解是 Spring 提供的。
然后我们看一下该注解的官方注释:
Indicates one or more component classes to import — typically @Configuration classes.
Provides functionality equivalent to the <import/> element in Spring XML. Allows for importing @Configuration classes, ImportSelector and ImportBeanDefinitionRegistrar implementations, as well as regular component classes (as of 4.2; analogous to AnnotationConfigApplicationContext.register).
@Bean definitions declared in imported @Configuration classes should be accessed by using @Autowired injection. Either the bean itself can be autowired, or the configuration class instance declaring the bean can be autowired. The latter approach allows for explicit, IDE-friendly navigation between @Configuration class methods.
May be declared at the class level or as a meta-annotation.
If XML or other non-@Configuration bean definition resources need to be imported, use the @ImportResource annotation instead.
我们将其中我们关心的重要部分提取出来翻译整理如下:
该注解可导入一个或多个组件类——通常是Configuration类。
允许导入@Configuration类、ImportSelector接口和ImportBeanDefinitionRegistrar接口的实现,以及普通类(从4.2版本开始)。
@Import注解可以在类上声明,也可以作为元注解声明在其他注解上。
那么 @Import 注解到底有什么作用和优势呢?
记住下面几句话:
导入配置。
从各个地方、通过各种方式导入配置。
在你需要的时候,从各个地方、通过各种方式导入配置。
在你需要的时候,从各个地方、通过各种方式导入并改造成你喜欢的配置。
下面我们通过示例讲 4 种官方注释给出的导入类型,分别是:
普通类
@Configuration类
ImportSelector接口实现
ImportBeanDefinitionRegistrar接口实现
普通类
普通类不必啰嗦,有手就行。
public class Circle {
}
@Configuration
@Import({Circle.class})
public class MainConfig {
}
导入@Configuration类
我们建立三个不同的模块,MainModule, Module1, Module2。
让 MainModule 引入 Module1、Module2依赖。
在 MainModule 中创建 MainConfig 类如下:
@Configuration
@Import({Config1.class, Config2.class})
public class MainConfig {
}
很明显,Config1,Config2 分别属于2个模块,如下:
@Configuration
public class Config1 {
@Bean
public String config1() {
return "我是config1配置类!";
}
}
@Configuration
public class Config2 {
@Bean
public String config2() {
return "我是config2配置类!";
}
}
在 MainModule 中创建测试类看是否生效:
@Test
void contextLoads() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
for (String name : context.getBeanDefinitionNames()) {
System.out.println(String.format("%s->%s", name, context.getBean(name)));
}
}
测试结果如下:
mainConfig->com.example.annotation.config.MainConfig$$EnhancerBySpringCGLIB$$a98d5b6a@55a609dd
com.example.module1.config1->com.example.module1.config.Config1$$EnhancerBySpringCGLIB$$72aca5d0@4afd21c6
config1->我是config1配置类!
com.example.module2.config2->com.example.module2.config.Config2$$EnhancerBySpringCGLIB$$72aca5d0@4afd21c6
config2->我是config2配置类!
ImportSelector接口实现
首先我们需要认识一下 ImportSelector 接口:
public interface ImportSelector {
String[] selectImports(AnnotationMetadata importingClassMetadata);
@Nullable
default Predicate<String> getExclusionFilter() {
return null;
}
}
只有一个需要实现的方法:
selectImports
参数 AnnotationMetadata 是什么?
翻译为注解元数据。
有什么用?
用来获取被@Import标注的类上面所有的注解信息。
String[] 是什么?
返回需要导入的类名的数组,可以是任何普通类,配置类。
上示例:
创建一个配置类
@Configuration
public class Config {
@Bean
public String name() {
return "公众号:JavaCode";
}
}
定义一个ImportSelectors实现类
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{
Config.class.getName()
};
}
}
上述代码中需要说明一下,Config.class.getName() 得到的是类的全类名,也就是[包名.类名],也就是com.example.annotation.pojo.Config。
导入MyImportSelector
@Import({MyImportSelector.class})
public class MainConfig {
}
这时候有人问了:
这里怎么没有 @Configuration 注解?
没关系哈,虽然 @Import 注解通常是与 @Configuration 注解一起使用的,但不是绝对必要的。
ImportBeanDefinitionRegistrar接口实现
首先我们还是先认识一下 ImportBeanDefinitionRegistrar 接口:
public interface ImportBeanDefinitionRegistrar {
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
}
}
可以看到只有2个方法,第一个方法调用第二个方法,所以我们就只看第二个方法就好了。
AnnotationMetadata 我们前边说过了:
用来获取被@Import标注的类上面所有的注解信息。
BeanDefinitionRegistry 呢?
它是一个接口,内部提供了注册bean的各种方法,用于我们手动注册bean。
上示例:
创建一个 Java 类
public class Rectangle {
public void sayHi() {
System.out.println("Rectangle sayHi()");
}
}
创建 ImportBeanDefinitionRegistrar 实现类
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Rectangle.class);
// 注册一个名字叫做 rectangle 的 bean
registry.registerBeanDefinition("rectangle", rootBeanDefinition);
}
}
总结
第一种:
我们有什么就可以导什么。
第二种:
我们可以把分散的配置集中起来,更加清晰和有组织。
第三种:
除了我们模块现有的配置,你只要能拿到类的全类名,就能注册进来。
第四种:
我们不光能到处拿,我们还能拿来以后随便改!
以上四种方式就实现了我们当初的豪言:
导入配置。
从各个地方、通过各种方式导入配置。
在你需要的时候,从各个地方、通过各种方式导入配置。
在你需要的时候,从各个地方、通过各种方式导入并改造成你喜欢的配置。
● 学会@ConfigurationProperties月薪过三千

不是银趴~是@Import!的更多相关文章
- [Python设计模式] 第2章 商场收银软件——策略模式
github地址: https://github.com/cheesezh/python_design_patterns 题目 设计一个控制台程序, 模拟商场收银软件,根据客户购买商品的单价和数量,计 ...
- 金三银四求职季,前端面试题小梳理(HTML、CSS、JS)
好久没写学习记录,最近太多事,又到一年求职季,都说金三银四求职季,自己也做一下最近学习的一些前端面试题梳理,还是个小白,写的不对请指正,不胜感激. HTML篇 html语义化 用语义化的代码标签书写, ...
- 一个excel(20M)就能干趴你的poi,你信吗?
自从上一篇:一个普通类就能干趴你的springboot,你信吗?后,很巧的是这次又发现一个问题,所以有了这篇文章,还是想沿用上篇的”流水帐“的方式查找问题和解决问题.这篇文章主要是因为使用POI导入一 ...
- 金三银四,磨砺锋芒;剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)上
金三银四,磨砺锋芒:剑指大厂,扬帆起航(2020年最全大厂WEB前端面试题精选)上 引言 元旦匆匆而过,2020年的春节又接踵而来,大家除了忙的提着裤子加班.年底冲冲冲外,还有着对于明年的迷茫和期待! ...
- 金三银四科学找工作,用python大数据分析一线城市1000多份岗位招聘需求
文章每周持续更新,各位的「三连」是对我最大的肯定.可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇) 每年的三四月份是招聘高峰,也常被大家称为金三银四黄金招聘期,这时候上一 ...
- 备战金三银四!一线互联网公司java岗面试题整理:Java基础+多线程+集合+JVM合集!
前言 回首来看2020年,真的是印象中过的最快的一年了,真的是时间过的飞快,还没反应过来年就夸完了,相信大家也已经开始上班了!俗话说新年新气象,马上就要到了一年之中最重要的金三银四,之前一直有粉丝要求 ...
- ES6模块import细节
写在前面,目前浏览器对ES6的import支持还不是很好,需要用bable转译. ES6引入外部模块分两种情况: 1.导入外部的变量或函数等: import {firstName, lastName, ...
- spring源码分析之@ImportSelector、@Import、ImportResource工作原理分析
1. @importSelector定义: /** * Interface to be implemented by types that determine which @{@link Config ...
- Python标准模块--import
1 模块简介 作为一个Python初学者,你首先要学会的知识就是如何引入其它模块或者包.但是,我发现有些开发者虽然使用Python很多年,依然不了解Python引入机制的灵活性.这篇文章,我们就会研究 ...
- css和@import区别用法
css和@import都是调用外部样式表的方法. 一.用法 (1)link: <link rel="stylesheet" type="text/css" ...
随机推荐
- 秋招还没Offer怎么办?
如果你是双非院线.没有实习经历.没有出众的技术(算法没刷一千道,也没做过 Spring Cloud 项目).现在还没有面试(或只有少量的面试).并且目前还没有 Offer,那么恭喜你,你和目前大部分同 ...
- nacos-mysql.sql
https://github.com/alibaba/nacos/blob/master/distribution/conf/nacos-mysql.sql # Nacos安装 /home/nacos ...
- 算法解析:LeetCode——机器人碰撞和最低票价
摘要:本文由葡萄城技术团队原创.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 机器人碰撞 问题: 现有 n 个机器人,编号从 1 开始,每个机器人包含在路 ...
- .net 温故知新【13】:Asp.Net Core WebAPI 使用依赖注入DI
一.使用DI注入 在之前的文章中已经讲过DI的概念(.net 温故知新:[7]IOC控制反转,DI依赖注入),基于控制台程序演示了DI依赖注入的使用,基于Microsoft.Extensions.De ...
- 题解 P7325
前言 数学符号约定 \(a,b,p\):表示任意自然数. \(F_x\):表示广义斐波那契数列的第 \(x\) 项. \(f_x\):表示普通斐波那契数列的第 \(x\) 项. 如非特殊说明,将会按照 ...
- 格局决定结局,进化还是毁灭,Prompt在其中扮演什么角色
GPT 时代, Prompt 的价值你们可能不懂 最近, OpenAI 推出了基于 GPT 模型的 GPTs 以及 Agent Stroe 系统,引发广泛关注.业内讨论热点主要集中在吸引用户体验方面. ...
- windows10 使用 USB 无线网卡的热点功能
一.概述 在某宝上买了一个 COMFAST CF-727B 的无线模块,由于笔记本电脑一直使用不上,所以放了很久.多年后我来到了一个公司,遇到了我此生最想吐槽的网管,简直不敢想象几十人的办公室,居然能 ...
- 栈与队列应用:逆波兰计算器(逆波兰表达式;后缀表达式)把运算符放到运算量后边 && 中缀表达式转化为后缀表达式
1 //1.实现对逆波兰输入的表达式进行计算如(2-1)*(2+3)= 5 就输入2 1 - 2 3 + * //先把2 1 压栈 遇到-弹栈 再把2 3压进去 遇到+弹栈 最后遇到*弹栈 2 //2 ...
- Android 应用接入 Firebase Crashlytics 进行崩溃分析上报
前言 所在公司的项目中有一款应用应客户要求,需要接入 Firebase Crashlytics,在此提前练手,也做个总结.本文以最新的 Gradle 7.5 为例,如果 Gradle 版本比较低,添加 ...
- Android的内部存储和外部存储怎么区分?
1.定义 内部存储:内部存储位于Android手机系统的data/data/<包名>这个目录下,内部存储是私有的,主要用于存储系统和应用程序的某些数据,对于其他应用程序来说是不可见的,并且 ...