当前位置: 首页 > 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.微服务基…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

C++ 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

SpringTask-03.入门案例

一.入门案例 启动类&#xff1a; package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

Python 训练营打卡 Day 47

注意力热力图可视化 在day 46代码的基础上&#xff0c;对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...

HTML前端开发:JavaScript 获取元素方法详解

作为前端开发者&#xff0c;高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法&#xff0c;分为两大系列&#xff1a; 一、getElementBy... 系列 传统方法&#xff0c;直接通过 DOM 接口访问&#xff0c;返回动态集合&#xff08;元素变化会实时更新&#xff09;。…...

41道Django高频题整理(附答案背诵版)

解释一下 Django 和 Tornado 的关系&#xff1f; Django和Tornado都是Python的web框架&#xff0c;但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架&#xff0c;鼓励快速开发和干净、实用的设计。它遵循MVC设计&#xff0c;并强调代码复用。Django有…...

安宝特方案丨从依赖经验到数据驱动:AR套件重构特种装备装配与质检全流程

在高压电气装备、军工装备、石油测井仪器装备、计算存储服务器和机柜、核磁医疗装备、大型发动机组等特种装备生产型企业&#xff0c;其产品具有“小批量、多品种、人工装配、价值高”的特点。 生产管理中存在传统SOP文件内容缺失、SOP更新不及、装配严重依赖个人经验、产品装…...

2025年上海市“星光计划”第十一届职业院校技能大赛 网络安全赛项技能操作模块样题

2025年上海市“星光计划”第十一届职业院校技能大赛 网络安全赛项技能操作模块样题 &#xff08;二&#xff09;模块 A&#xff1a;安全事件响应、网络安全数据取证、应用安全、系统安全任务一&#xff1a;漏洞扫描与利用:任务二&#xff1a;Windows 操作系统渗透测试 :任务三&…...