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

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、注意事项 二、接口功能介绍 描述&#xff1a;ImportBeanDefinitionRegistrar接口是也是spring的扩展点之一,它可以支持我们自己写的代码封装成BeanDefinition对象,注册到Spring容器中&#xff0c;功能类似于注…...

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.开放-封闭原则

这个原则其实是有两个特征&#xff0c;一个是说‘对于扩展是开放的(Open for extension)&#xff0c;另一个是说‘对于更改是封闭的(Closed for modification)[ASD]。...

oracle递归with子句

比如现在想获取开始日期到结束日期每个月的月底日期&#xff0c;这个时候可以通过递归实现&#xff1a; --通过递归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 图文安装教程&#xff08;附安装包&#xff09;_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镜像&#xff0c;关于修改字体的问题 自编译onlyoffice镜像来自于 https://blog.csdn.net/Gemini1995/article/details/132427908 该镜像里面没有documentserver-generate-allfonts.sh文件&#xff0c;所以需要自己创建一个&#xff08;建议放在/usr/b…...

1.wifi开发,wifi连接初次连接电脑没有识别,搭建环境

wifi连接初次连接电脑没有识别 1.不识别可能是线的问题&#xff0c;即使wifi的灯亮了&#xff0c;虽然串口却没有找到。所以解决方法就是重新来一个usb的线 一。初步使用 &#xff08;1&#xff09;使用ESP烧写工具&#xff08;选择esp8266&#xff09; &#xff08;2&#xf…...

【JAVA-Day25】解密进制转换:十进制向R进制和R进制向十进制的过程

解密进制转换&#xff1a;十进制向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&#xff1b; 根据资料&#xff0c;Qt自带SQLite数据库&#xff0c;不需要再单独安装&#xff0c;默认情况下&#xff0c;使用SQLite版本3&#xff0c;驱动程序为***QSQLITE***&#xff1b; 首先创建项目&#xff1b;在 Build system 中应选中qmake&#xff0c;…...

ChatGPT AIGC 完成各省份销售动态可视化分析

像这样的动态可视化由人工智能ChatGPT AIGC结合前端可视化技术就可以实现。 Prompt:请使用HTML,JS,Echarts 做一个可视化分析的案例,地图可视化,数据可以随机生成,请写出完整的代码 完整代码复制如下: <!DOCTYPE html> <html> <head><meta char…...

基于SpringBoot+Vue的餐饮管理系统设计与实现

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…...

2023 亲测好用版VScode配置文件

tasks.json {"tasks": [{"type": "cppbuild","label": "g++",// 调试会话开始前执行的任务,一般为编译程序,c++为g++, c为gcc 和launch中preLaunchTask保持一致// "command": "D:/Users/Downloads/ming…...

jmeter基础压力教程

Jmeter基础压力测试教程 一、安装Jmeter&#xff1b; 安装需求&#xff1a;1. JDK 8.0.91安装包&#xff08;最新即可&#xff0c;配置环境变量&#xff09; 2. Badboy2.25脚本录制工具&#xff08;注&#xff1a;Jmeter3.0与badboy2.0不兼容&#xff09; Jmerter安装包…...

图片格式大全

青春不能回头&#xff0c;青春也没有终点。 大全介绍 图片格式有多种&#xff0c;每种格式都有其独特的特性和用途。以下是一些常见的图片格式以及它们的介绍&#xff1a; JPEG&#xff08;Joint Photographic Experts Group&#xff09;&#xff1a; 文件扩展名&#xff1a;…...

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实现简单线性模型:搭建、构造损失函数、计算损失值

#【中秋征文】程序人生&#xff0c;中秋共享# 目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入库 1. 定义线性模型linear_model 2. 定义损失函数loss_function 3. 定义数据 4. 调用函数 一、实验介绍 使用Numpy实现 线性模型搭…...

springcloud3 分布式事务-seata的四种模式总结以及异地容灾

一 seata四种模式比较 1.1 seata的4种模式比较 二 seata的高可用 2.1架构 1.建TC服务集群非常简单&#xff0c;启动多个TC服务&#xff0c;注册到nacos即可。 2.做异地多机房容灾&#xff0c;比如一个TC集群在上海&#xff0c;另一个TC集群在杭州&#xff0c; 3.微服务基…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

VisualXML全新升级 | 新增数据库编辑功能

VisualXML是一个功能强大的网络总线设计工具&#xff0c;专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑&#xff08;如DBC、LDF、ARXML、HEX等&#xff09;&#xff0c;并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...

解析“道作为序位生成器”的核心原理

解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制&#xff0c;重点解析"道作为序位生成器"的核心原理与实现框架&#xff1a; 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...

【iOS】 Block再学习

iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...