Spring学习之ImportBeanDefinitionRegistrar接口
一、本文内容分类
1、接口功能
 2、接口运用场景
 3、使用案例
 4、注意事项
二、接口功能介绍
描述:ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,它可以支持我们自己写的代码封装成BeanDefinition对象,注册到Spring容器中,功能类似于注解@Service @Component。
 很多三方框架集成Spring的时候,都会通过该接口,实现扫描指定的类,然后注册到spring容器中,比如Mybatis中的Mapper接口,springCloud中的FeignClient接口,都是通过该接口实现的自定义注册逻辑。
1、ImportBeanDefinitionRegistrar接口实现类,只能通过@Import注解的方式来注入,通常把@Import修饰在启动类或配置类。
2、使用@Import,如果括号中的类是ImportBeanDefinitionRegistrar的实现类,启动时会触发ImportBeanDefinitionRegistrar接口的方法,将其中要注册的类注册成bean。
3、实现该接口的类拥有注册bean的能力。
//接口所有抽象方法,合并看就一个注册BeanDefinition的方法
public interface ImportBeanDefinitionRegistrar {//把自定义的类封装成BeanDefinition对象,注册到Spring里面去default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {registerBeanDefinitions(importingClassMetadata, registry);}//我们平时重写这个就可以了default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {}
}
三、接口运用场景
四、使用案例
1、案例1
自定义业务类UserServiceTest,通过ImportBeanDefinitionRegistrar将注册Spring容器中。在通过spring容器获取Bean=UserServiceTest
//业务类
public class UserServiceTest {/*** 获取用户名称* @return 用户名称*/public String getUserName(){return "测试";}
}
ImportBeanDefinitionRegistrar实现类
//注意这里不能加注解,要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {//业务类转成bd,注册到spring容器中注入@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//1、通过Bd工具类生成bd对象,只是这个Db对象比较纯洁没有绑定任何类BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();//2、设置bd绑定的类型beanDefinition.setBeanClass(UserServiceTest.class);//3、注册到spring容器中registry.registerBeanDefinition("userServiceTest",beanDefinition);}
}@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfigClassTest {//在配置类导入ImportBeanDefinitionRegistrar实现类
}
//测试
public static void main(String[] args) {AnnotationConfigApplicationContext AnnotationConfigApplicationContext =new AnnotationConfigApplicationContext(AppConfigClassTest.class);UserServiceTest userServiceTest = AnnotationConfigApplicationContext.getBean("userServiceTest", UserServiceTest.class);String userName = userServiceTest.getUserName();System.out.println(userName);
}
如果只是把业务类注册到Spring容器中我们通过其他注解就可以了,那么ImportBeanDefinitionRegistrar有没有更高级的玩法。
2、案例2
public interface UserServiceTestInterface {public void list();
}
//因为是接口,但是spring的容器里面是不允许注入接口的,只能是接口的实现类。如果我们写个去实现接口,那就没有什么意义了,没必要搞得那么复杂,这次我们通过代理类来完成对接口的实现。public class MyInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理类逻辑代码");return null;}
}
//注意这里不能加注解,要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//通过工具类生成一个bd,只是这个Db对象比较纯洁没有绑定任何类BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();//设置Bean的类型MyInvocationHandler,类型是实现类的类型,不是接口类型。因为在实例化的时候,调用的是设置类型所以对应的构造方法。beanDefinition.setBeanClass(MyInvocationHandler.class);//注册到Spring容器中进去registry.registerBeanDefinition("userServiceTest",beanDefinition);}
}//通过配置类,导入ImportBeanDefinitionRegistrar的实现类
@Configuration
@Import(MyImportBeanDefinitionRegistrar.class)
public class AppConfigClassTest {
}
测试
public static void main(String[] args) {AnnotationConfigApplicationContext AnnotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfigClassTest.class);//通过name获取Bean,注意此时的bean类型不是UserServiceTestInterface类型,而是MyInvocationHandlerObject userServiceTestInterface = AnnotationConfigApplicationContext.getBean("userServiceTest");if(userServiceTestInterface instanceof MyInvocationHandler){//代码实际会走到这里,把object转成带代理类。MyInvocationHandler u = (MyInvocationHandler) userServiceTestInterface;//生成接口UserServiceTestInterface的代理对象UserServiceTestInterface o = (UserServiceTestInterface) Proxy.newProxyInstance(MainTest.class.getClassLoader(), new Class[]{UserServiceTestInterface.class}, u);}
}
3、案例3
定义一个业务接口,通过FactoryBean+InvocationHandler来生成该接口的代理类,无需手动写业务接口的实现类,很多底层框架就是这样实现的。
InvocationHandler:主要是通过Invoke方法来拦截业务接口的方法
FactoryBean:主要是用来将生成的代理类。
ImportBeanDefinitionRegistrar:在这里的作用就是帮忙我们把自定义的FactoryBean注册到Spring中
//业务接口
public interface UserServiceTestInterface {public void list();
}
自定义FactoryBean这样我们控制Bean的创建的过程,实现InvocationHandler用来拦截业务接口的方法。
//创建代理类,代理UserServiceTestInterface接口,UserServiceTestInterface接口方法在执行前后都会被invoke方法拦截
//FactoryBean可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程
public class MyFactoryBean implements FactoryBean, InvocationHandler {//为了使这个类更好地扩展。创建更多的接口,我们定义一个参数,让他们通过参数传递进来。private Class classs;//添加一个有参的构造方法。public MyFactoryBean(Class classs){this.classs = classs;}//拦截Class的所有方法@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("diaoyonlejiekou123");return null;}//返回bean的对象。spring会自动把它add到容器里面去。@Overridepublic Object getObject() throws Exception {Class[] clazzs = new Class[]{classs};//目标类集合。//通过proxy来得到代理对象。本来最有一个参数需要穿代理类对象,但因为本类实现了InvocationHandler,所以只需传thisObject proxy = Proxy.newProxyInstance(this.getClass().getClassLoader(), clazzs, this);return proxy;//返回的这个对象,会把加到spring的容器中。}//返回要添加到容器里bean的类型@Overridepublic Class<?> getObjectType() {return this.classs;}
}
自定义ImportBeanDefinitionRegistrar实现类,把我们自定义的FactoryBean注册到Spring中。
//注意这里不能加注解,要通过Import导入进去。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//通过工具类生成一个bd,只是这个Db对象比较纯洁没有绑定任何类BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition();//为什么要转成GenericBeanDefinition这种类型。因为GenericBeanDefinition有更多修改bd属性的方法。后面我会介绍为什么要修改属性。GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionBuilder.getBeanDefinition();//这里很重要。getConstructorArgumentValues是为了获取该bd的所有构造方法,因为我们重写了有参构造方法,所有我们需要带参数过去 //不然spring没法帮我们实例化,addGenericArgumentValue是添加参数,该代码会执行两步//第一步是匹配对应的构造方法,第二步是实例化。beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(UserServiceTestInterface.class.getName());//因为代理对象类型的,实例化的时候走的是代理类的构造方法beanDefinition.setBeanClass(MyFactoryBean.class);//注册bdregistry.registerBeanDefinition("userServiceTest",beanDefinition);}
}
测试
public static void main(String[] args) {AnnotationConfigApplicationContext AnnotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfigClassTest.class);//通过name获取BeanObject userServiceTestInterface = AnnotationConfigApplicationContext.getBean("userServiceTest");//针对这种场景Bean的类型是,通过FactoryBean的getObjectType方法返回的。UserServiceTestInterface u = (UserServiceTestInterface) userServiceTestInterface;u.list();
}
相关文章:
Spring学习之ImportBeanDefinitionRegistrar接口
一、本文内容分类 1、接口功能 2、接口运用场景 3、使用案例 4、注意事项 二、接口功能介绍 描述:ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,它可以支持我们自己写的代码封装成BeanDefinition对象,注册到Spring容器中,功能类似于注…...
React 全栈体系(八)
第四章 React ajax 三、案例 – github 用户搜索 2. 代码实现 2.3 axios 发送请求 Search /* src/components/Search/index.jsx */ import React, { Component } from "react"; import axios from axiosexport default class Search extends Component {search …...
 
4.开放-封闭原则
这个原则其实是有两个特征,一个是说‘对于扩展是开放的(Open for extension),另一个是说‘对于更改是封闭的(Closed for modification)[ASD]。...
oracle递归with子句
比如现在想获取开始日期到结束日期每个月的月底日期,这个时候可以通过递归实现: --通过递归with子句获取开始日期到结束日期每个月的月末日期 WITH date_range (month_start, month_end) AS (SELECT TRUNC(to_date(bdate,yyyy-mm-dd), MM),LAST_DAY(to_…...
 
如何在Proteus进行STM32F103C8T6模拟以及keil5开发
一、下载Proteus 8和keil5 最新版 Proteus 8.15 Professional 图文安装教程(附安装包)_proteus密钥_main工作室的博客-CSDN博客Keil uVision5 5.38官方下载、安装及注册教程_keil uvision5下载_这是乐某的博客-CSDN博客 二、新建STM32F103C8项目 接下来…...
 
C# OpenCvSharp 图片模糊检测(拉普拉斯算子)
效果 项目 代码 using OpenCvSharp; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Windows.Forms.VisualStyl…...
 
志高团队:广阔前景 全新的投资理财体验
当今时代,数字金融迅猛发展,投资理财领域正在经历前所未有的重大变革。作为加拿大华企联合会控股旗下的重要项目,恒贵即将启动,旨在为广大投资者带来全新的投资理财体验。这一创新项目的优势和广阔前景受到了业内观察机构的广泛关注和期待。 恒贵作为一家全新的P2C多元化投资理…...
 
基于自编译的onlyoffice镜像,关于修改字体的问题
基于自编译的onlyoffice镜像,关于修改字体的问题 自编译onlyoffice镜像来自于 https://blog.csdn.net/Gemini1995/article/details/132427908 该镜像里面没有documentserver-generate-allfonts.sh文件,所以需要自己创建一个(建议放在/usr/b…...
 
1.wifi开发,wifi连接初次连接电脑没有识别,搭建环境
wifi连接初次连接电脑没有识别 1.不识别可能是线的问题,即使wifi的灯亮了,虽然串口却没有找到。所以解决方法就是重新来一个usb的线 一。初步使用 (1)使用ESP烧写工具(选择esp8266) (2…...
 
【JAVA-Day25】解密进制转换:十进制向R进制和R进制向十进制的过程
解密进制转换:十进制向R进制和R进制向十进制的过程 一、什么是进制转换1.1 进制1.2 进制转换 二、十进制转R进制2.1 转换算法2.2 示例代码 三、R进制转十进制3.1 转换算法3.2 示例代码 四、总结参考资料 ) 博主 默语带您 Go to New World. ✍ 个人主页—— 默语 的…...
牛客网字节面试算法刷题记录
NC78 反转链表 public ListNode ReverseList (ListNode head) {if(headnull) return head;ListNode phead.next,q,tailhead;tail.next null;while(p!null){q p.next;p.next tail;tail p;p q;}return tail;} NC140 排序 冒泡排序 public int[] MySort (int[] arr) {for…...
 
QT连接Sqlite
使用QTCreator; 根据资料,Qt自带SQLite数据库,不需要再单独安装,默认情况下,使用SQLite版本3,驱动程序为***QSQLITE***; 首先创建项目;在 Build system 中应选中qmake,…...
 
ChatGPT AIGC 完成各省份销售动态可视化分析
像这样的动态可视化由人工智能ChatGPT AIGC结合前端可视化技术就可以实现。 Prompt:请使用HTML,JS,Echarts 做一个可视化分析的案例,地图可视化,数据可以随机生成,请写出完整的代码 完整代码复制如下: <!DOCTYPE html> <html> <head><meta char…...
 
基于SpringBoot+Vue的餐饮管理系统设计与实现
前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 👇🏻…...
2023 亲测好用版VScode配置文件
tasks.json {"tasks": [{"type": "cppbuild","label": "g++",// 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc 和launch中preLaunchTask保持一致// "command": "D:/Users/Downloads/ming…...
 
jmeter基础压力教程
Jmeter基础压力测试教程 一、安装Jmeter; 安装需求:1. JDK 8.0.91安装包(最新即可,配置环境变量) 2. Badboy2.25脚本录制工具(注:Jmeter3.0与badboy2.0不兼容) Jmerter安装包…...
 
图片格式大全
青春不能回头,青春也没有终点。 大全介绍 图片格式有多种,每种格式都有其独特的特性和用途。以下是一些常见的图片格式以及它们的介绍: JPEG(Joint Photographic Experts Group): 文件扩展名:…...
 
5.14.1.2 Get Log Page – Smart Log
SMART / Health Information (Log Identifier 02h) smart log 可通过nvme cli获取如下: 同样也可以通过get-log 命令获取到原始数据如下: 此日志页用于提供SMART和常用的helath 信息。所提供的信息在控制器的使用寿命内,并在整个power cycle前后都保留。要访问控制器日志…...
 
【深度学习实验】线性模型(一):使用NumPy实现简单线性模型:搭建、构造损失函数、计算损失值
#【中秋征文】程序人生,中秋共享# 目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入库 1. 定义线性模型linear_model 2. 定义损失函数loss_function 3. 定义数据 4. 调用函数 一、实验介绍 使用Numpy实现 线性模型搭…...
 
springcloud3 分布式事务-seata的四种模式总结以及异地容灾
一 seata四种模式比较 1.1 seata的4种模式比较 二 seata的高可用 2.1架构 1.建TC服务集群非常简单,启动多个TC服务,注册到nacos即可。 2.做异地多机房容灾,比如一个TC集群在上海,另一个TC集群在杭州, 3.微服务基…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
 
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
 
高等数学(下)题型笔记(八)空间解析几何与向量代数
目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...
 
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
 
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
 
【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...
 
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
