Spring-ImportSelector接口功能介绍
ImportSelector接口是至spring中导入内部类或者外部类的核心接口,只需要其定义的方法内返回需要创建bean的class字符串就好了,比如:当我们引入一个外部share包,我们拿到里面的Class返回出去,就能得到这个bean,是多么神奇的事情,前提是这个类不是接口哦。
ImportSelector往往结合@Import注解一起使用,可以参考我的这篇文章@Import注解介绍
public interface ImportSelector {//返回类的字符串数组,也就是要创建的bean的className,比如userService.class.getName()//被创建的bean是在其他bean(@Component、@Service等注解修饰的Bean)创建之前创建的String[] selectImports(AnnotationMetadata importingClassMetadata);
}
二、使用案例
通过返回Class的字符串来创建bean
//定义一个业务类
public class UserServiceTest {public String getUserName(){return "测试";}
}//实现ImportSelector接口
public class MyImportSelect implements ImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {//返回要注册到Spring容器的Class集合return new String[]{UserServiceTest.class.getName()};}
}//配置类
@Configuration
@Import(MyImportSelect.class) //导入我们实现ImportSelector的类。
public class AppConfigClassTest {
}
测试
public class MainTest {public static void main(String[] args) {AnnotationConfigApplicationContext AnnotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfigClassTest.class);//这里我们不能通过“userServiceTest”来获取bean,因为这个bean的name不是userServiceTest,而是userServiceTest.getClass().getName()//因为bean的别名成功器,只是针对像注解@Service等注解,会生成一个首字母小写的BeanNameUserServiceTest userServiceTest = AnnotationConfigApplicationContext.getBean(UserServiceTest.class);System.out.println(((UserServiceTest)userServiceTest).getUserName());}
}
下面说下源码是怎么实现的,可以跳转到@Import注解介绍
//这里就直接跳到ConfigurationClassPostProcessor处理@Import注解的逻辑上
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter, boolean checkForCircularImports) {//如果importCandidates为空直接return,为什么会有这个,因为下面代码可能会递归调用processImports,就比如Import一个类,这个类也带了@Import注解,那就会在调用一次processImports方法if (importCandidates.isEmpty()) {return;}for (SourceClass candidate : importCandidates) {if (candidate.isAssignable(ImportSelector.class)) {//1、import的类,实现了ImportSelector接口Class<?> candidateClass = candidate.loadClass();//利用反射Class实例化对象,这个对象不是代理对象不要搞混了。ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,this.environment, this.resourceLoader, this.registry);Predicate<String> selectorFilter = selector.getExclusionFilter();if (selectorFilter != null) {exclusionFilter = exclusionFilter.or(selectorFilter);}if (selector instanceof DeferredImportSelector) {this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);} else {//调用ImportSelector接口里面的selectImports方法,拿到返回值Class集合。在通过递归的方式嗲用processImports挨个解析每一个ClassString[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());//转成SourceClass集合Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);//再次调用processImports方法processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);}} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {。。。。。。} else {//3、ImportSelector和ImportBeanDefinitionRegistrar都没有实现this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());//进一步解析其他注解,比如@Component @Import等最后会把configClass注册到Spring容器中。processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);}}
}
看下instantiateClass方法做了什么
//创建实例对象
static <T> T instantiateClass(Class<?> clazz, Class<T> assignableTo, Environment environment, ResourceLoader resourceLoader, BeanDefinitionRegistry registry) {ClassLoader classLoader = (registry instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) registry).getBeanClassLoader() : resourceLoader.getClassLoader());T instance = (T) createInstance(clazz, environment, resourceLoader, registry, classLoader);ParserStrategyUtils.invokeAwareMethods(instance, environment, resourceLoader, registry, classLoader);return instance;
}//调用createInstance方法创建实例对象
private static Object createInstance(Class<?> clazz, Environment environment, ResourceLoader resourceLoader, BeanDefinitionRegistry registry, @Nullable ClassLoader classLoader) {Constructor<?>[] constructors = clazz.getDeclaredConstructors();。。。。。。。return BeanUtils.instantiateClass(clazz);//通过Bean的工具类生成实例对象
}
相关文章:
Spring-ImportSelector接口功能介绍
ImportSelector接口是至spring中导入内部类或者外部类的核心接口,只需要其定义的方法内返回需要创建bean的class字符串就好了,比如:当我们引入一个外部share包,我们拿到里面的Class返回出去,就能得到这个bean,是多么神…...
YOLOv5如何训练自己的数据集
文章目录 前言1、数据标注说明2、定义自己模型文件3、训练模型4、参考文献 前言 本文主要介绍如何利用YOLOv5训练自己的数据集 1、数据标注说明 以生活垃圾数据集为例子 生活垃圾数据集(YOLO版)点击这里直接下载本文生活垃圾数据集 生活垃圾数据集组成&…...
李航老师《统计学习方法》第1章阅读笔记
1.1 统计学习 统计学习的特点 统计学习:计算机基于数据构建概率统计模型并运用模型对数据进行预测与分析 现在人们提及机器学习时,往往指统计机器学习,所以可以认为本书介绍的是机器学习方法 统计学习的对象 统计学习研究的对象是数据(data)…...
基于微信小程序的背单词学习激励系统设计与实现(源码+lw+部署文档+讲解等)
文章目录 前言用户微信端的主要功能有:管理员的主要功能有:具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉…...
VScode调试复杂C/C++项目
以前都是用的VScode调试c/cpp的单个文件的编译和执行, 但是一遇到大型项目一般就用gdb了, gdb的调试效率和VScode差距还是比较大的, 但最近发现VScode其实也能调试复杂的cpp项目, 所以记录一下. 首先明确一下几点: 首先cpp文件需要经过编译, 生成可执行文件, 然后通过运行/调…...
【Hash表】字母异位词分组-力扣 49 题
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…...
展示日志log4.properties
log4.properties 1.log4.properties 此时文件主要用于展示日志的输出的级别的信息。 # Set root category priority to INFO and its only appender to CONSOLE. #log4j.rootCategoryINFO, CONSOLE debug info warn error fatal log4j.rootCategoryinfo, CONSO…...
基于PLE结合卡尔曼滤波的RSSI定位算法matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ............................................................... for Num_xb Num_xb2Num_…...
uniapp项目实践总结(十九)版本更新和热更新实现方法
导语:当一个 APP 应用开发完成以后,就要上架应用商店,但有时候修改一些小问题或者推出一些活动,又不想频繁地提交应用商店审核,那么就可以使用应用内更新功能来进行应用的版本升级更新或热更新,下面就介绍一下实现的方法。 目录 准备工作原理分析实战演练案例展示准备工作…...
一起学数据结构(8)——二叉树中堆的代码实现
在上篇文章中提到,提到了二叉树中一种特殊的结构——完全二叉树。对于完全二叉树,在存储时,适合使用顺序存储。对于非完全二叉树,适合用链式存储。本文将给出完全二叉树的顺序结构以及相关的代码实现: 1. 二叉树的结构…...
Linux环境变量配置说明(配置jdk为例-摘录自尚硅谷技术文档)
配置环境变量的不同方法 Linux的环境变量可在多个文件中配置,如/etc/profile,/etc/profile.d/.sh,~/.bashrc,~/.bash_profile等,下面说明上述几个文件之间的关系和区别。 bash的运行模式可分为login shell和non-login shell。 例…...
idea常用插件笔记
文章目录 Free Mybatis Toollombok插件idea插件导出导入 idea提供了很多好用的插件,之前都装了的,但是换了下电脑,什么都没了,所以记录下方便以后用。 Free Mybatis Tool mybatis跳转插件,再也不用费力的找xml了。 l…...
搜索二叉树【C++】
文章目录 二叉搜索树二叉搜索树的模拟实现构造函数拷贝构造函数赋值运算符重载函数析构函数Insert循环递归 Erase循环递归 Find循环递归 二叉搜索树的应用K模型KV模型 完整代码普通版本递归版本 二叉搜索树 二叉搜索树又称为二叉排序树,它或者是一棵空树࿰…...
华为云云耀云服务器L实例评测|认识redis未授权访问漏洞 漏洞的部分复现 设置连接密码 redis其他命令学习
前言 最近华为云云耀云服务器L实例上新,也搞了一台来玩,期间遇到过MySQL数据库被攻击的情况,数据丢失,还好我有几份备份,没有造成太大的损失。昨天收到华为云的邮箱提醒,我的redis数据库没有设置密码&…...
快速安装NGINX
快速安装NGINX #安装依赖包 yum -y install gcc pcre pcre-devel zlib zlib-devel openssl openssl-devel#下载NGINX curl -O https://nginx.org/download/nginx-1.21.6.tar.gz#解压NGINX tar -zxvf nginx-1.21.6.tar.gz cd nginx-1.21.6.tar.gz#配置 ./configure --prefix/…...
一台电脑远程内网的另外一台电脑,禁止远程的电脑连接外网,只允许内网连接
一台电脑远程内网的另外一台电脑,禁止远程的电脑连接外网,只允许内网连接 1.找到右下角网卡图标,右键图标选择“打开网络和共享中心”。 3、点击“更改适配器设置”。 4、右键正在使用的网卡“本地连接”打开属性 5、找到“internet协…...
山西电力市场日前价格预测【2023-09-24】
日前价格预测 预测说明: 如上图所示,预测明日(2023-09-24)山西电力市场全天平均日前电价为496.09元/MWh。其中,最高日前电价为705.54元/MWh,预计出现在14: 30。最低日前电价为333.70元/MWh,预计…...
MQ---第二篇
系列文章目录 文章目录 系列文章目录一、RabbitMQ事务消息二、RabbitMQ死信队列、延时队列一、RabbitMQ事务消息 通过对信道的设置实现 channel.txSelect();通知服务器开启事务模式;服务端会返回Tx.Select-Okchannel.basicPublish;发送消息,可以是多条,可以是消费消息提交…...
C++ 创建文件并写入内容
文章目录 1.问题2.filesystem3.示例参考文献 1.问题 C 如何向指定路径的文件写入内容呢? 这里有几点要求: 如果目录不存在需要自动创建。如果文件不存在需要自动创建。以覆盖的方式写入内容。 2.filesystem C17 带来了一个新的库:filesy…...
微信小程序rich-text里面写多行溢出显示省略号在ios中不显示的问题
问题:微信小程序rich-text里面写多行溢出显示省略号在ios中不显示的问题 解决方法:需要给一个默认的div标签,在div写行内样式 overflow : hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-o…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
【论文笔记】若干矿井粉尘检测算法概述
总的来说,传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度,通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
