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

Spring boot 项目 Spring 注入 代理 并支持 代理对象使用 @Autowired 去调用其他服务

在这里插入图片描述

文章目录

    • 类定义与依赖注入
    • 方法解析
    • createCglibProxy
    • 注意事项
    • setApplicationContext 方法
    • createCglibProxy 方法

类定义与依赖注入

  • @Service: 标识这是一个 Spring 管理的服务类。
  • ApplicationContextAware: 实现该接口允许你在类中获取 ApplicationContext 对象,从而可以访问 Spring 容器中的所有 Bean。
  • @Autowired: 注入了 AutowireCapableBeanFactory,用于自动装配新创建的代理对象。

方法解析

  • invokeSendMessage
  • 此方法接收一个类名(对应于某个实现了 DeviceMessageInterface 的 Bean)和一个 SendMessage 对象作为参数。它首先通过 applicationContext.getBean() 获取目标 Bean 的实例,然后创建该实例的 CGLIB 代理,并调用代理的 sendMessage 方法。
  • invokeAllSendMessages
  • 遍历所有实现了 DeviceMessageInterface 接口的 Bean,并对每个 Bean 创建其 CGLIB 代理对象,随后调用代理的 sendMessage 方法。这使得你可以一次性对所有相关处理器发送消息。
  • invokeReceiveMessage
  • 类似于 invokeAllSendMessages,但它是为处理接收到的消息而设计的。它会尝试调用每个处理器的 receiveMessage 方法,并返回第一个非空的结果(如果有的话)。如果所有处理器都未能成功处理消息,则返回一个包含错误信息的 JSON 对象。

createCglibProxy

这是一个泛型方法,负责创建给定类的 CGLIB 代理。代理对象在调用任何方法时都会先打印出方法名称,执行完方法后再打印一次。此外,它还会使用 autowireCapableBeanFactory.autowireBean(proxyInstance) 来确保代理对象能够被正确地注入依赖。

注意事项

线程池未使用:虽然代码中注释掉了 ThreadPoolTaskExecutor taskExecutor,但如果你希望异步执行这些操作,可以考虑取消注释并利用线程池来并发处理任务。
异常处理:目前 invokeReceiveMessage 和 invokeAllSendMessages 中的异常只是简单地打印堆栈跟踪。根据你的需求,可能需要更复杂的错误处理逻辑。
CountDownLatch 未使用:你声明了 CountDownLatch countDownLatch 但没有实际使用它。如果你打算用于同步操作,请确保正确初始化并在适当的地方使用它。
JSON 异常处理:在构造返回的 JSON 对象时捕获了 JSONException,但实际上在这个上下文中不太可能发生此类异常,因为 put 方法不会抛出受检异常。

setApplicationContext 方法

setApplicationContext 方法实现了 ApplicationContextAware 接口中的方法,用于设置当前的 ApplicationContext。这个方法在 Spring 容器初始化时自动调用,允许你的类获取对整个应用上下文的访问权限。这对于需要直接与 Spring 容器交互或获取其他 Bean 的组件非常有用。

createCglibProxy 方法

createCglibProxy 方法使用了 CGLIB 库来创建一个给定类的代理对象,并且在方法调用前后打印日志信息。此外,它还使用了 Spring 的 AutowireCapableBeanFactory 来自动装配新创建的代理对象,确保它可以访问其他 Spring 管理的 Bean。

public <T> T createCglibProxy(Class<T> targetClass, String beanName) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(targetClass);enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method: " + method.getName());Object result = proxy.invokeSuper(obj, args);System.out.println("After method: " + method.getName());return result;}});T proxyInstance = (T) enhancer.create();autowireCapableBeanFactory.autowireBean(proxyInstance);return proxyInstance;
}
public <T> T createCglibProxy(Class<T> targetClass, String beanName) {

泛型方法声明:<T> 表示这是一个泛型方法,返回类型为 T。
参数:

  • targetClass: 目标类的 Class 对象,用于指定要代理的类。
  • beanName: 字符串类型的参数,代表目标 Bean 的名称(虽然在这个方法中没有直接使用)。
Enhancer enhancer = new Enhancer();
  • 创建 CGLIB 的 Enhancer 实例:Enhancer 是 CGLIB 中用来生成子类或代理类的核心类。
enhancer.setSuperclass(targetClass);
  • 设置父类:告诉 Enhancer 使用 targetClass 作为代理类的父类。这意味着代理类将继承 targetClass 的所有非私有方法。
enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method: " + method.getName());Object result = proxy.invokeSuper(obj, args);System.out.println("After method: " + method.getName());return result;}
});
  • 设置回调接口:MethodInterceptor 是 CGLIB 提供的一个接口,允许你在方法调用时插入自定义逻辑。这里通过匿名内部类实现了该接口。
    intercept 方法:
    • obj: 被代理的对象实例。
    • method: 当前被拦截的方法。
    • args: 方法参数列表。
    • proxy: MethodProxy 对象,提供了对原始方法的访问。
    • 日志记录:在调用实际方法之前和之后分别打印一条消息。
    • 调用父类方法:proxy.invokeSuper(obj, args) 调用了原始类的方法实现。
    • 返回结果:将原始方法的结果返回给调用者。
T proxyInstance = (T) enhancer.create();
  • 创建代理实例:enhancer.create() 方法根据配置创建并返回一个新的代理实例。这里强制转换为 T 类型,确保返回值与输入参数 targetClass 的类型一致。
autowireCapableBeanFactory.autowireBean(proxyInstance);
  • 自动装配依赖:使用 Spring 的 AutowireCapableBeanFactory 对代理实例进行自动装配,这一步骤使得代理对象能够像普通的 Spring Bean 一样获得依赖注入。
return proxyInstance;
  • 返回代理对象:最终返回创建好的代理对象,供调用方使用。
import org.json.JSONException;
import org.json.JSONObject;
import org.nuobeifu.dataprocessing.devicemessage.DeviceMessageInterface;
import org.nuobeifu.dataprocessing.devicemessage.entity.ReceiveMessage;
import org.nuobeifu.dataprocessing.devicemessage.entity.SendMessage;
import org.nuobeifu.dataprocessing.entity.vo.SysDeviceMessageExecuteTaskVO;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.CountDownLatch;@Service
public class CglibProxyService implements ApplicationContextAware {private ApplicationContext applicationContext;@Autowiredprivate AutowireCapableBeanFactory autowireCapableBeanFactory;//    @Autowired
//    private ThreadPoolTaskExecutor taskExecutor;private CountDownLatch countDownLatch;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;this.autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory();}public void invokeSendMessage(String className, SendMessage taskvo) {// 获取 Bean 实例DeviceMessageInterface instance = applicationContext.getBean(className, DeviceMessageInterface.class);// 创建 CGLIB 代理对象DeviceMessageInterface proxyInstance = createCglibProxy(instance.getClass(), className);// 调用 sendMessage 方法proxyInstance.sendMessage(taskvo);}public void invokeAllSendMessages(SendMessage taskvo) {try {// 获取所有实现 DeviceMessageInterface 的 BeanMap<String, DeviceMessageInterface> beans = applicationContext.getBeansOfType(DeviceMessageInterface.class);for (Map.Entry<String, DeviceMessageInterface> entry : beans.entrySet()) {String beanName = entry.getKey();DeviceMessageInterface instance = entry.getValue();// 创建 CGLIB 代理对象DeviceMessageInterface proxyInstance = createCglibProxy(instance.getClass(), beanName);// 调用 sendMessage 方法proxyInstance.sendMessage(taskvo);}} catch (Exception e) {e.printStackTrace();}}public JSONObject invokeReceiveMessage(String className, ReceiveMessage taskvo) {try {// 获取所有实现 DeviceMessageInterface 的 BeanMap<String, DeviceMessageInterface> beans = applicationContext.getBeansOfType(DeviceMessageInterface.class);for (Map.Entry<String, DeviceMessageInterface> entry : beans.entrySet()) {String beanName = entry.getKey();DeviceMessageInterface instance = entry.getValue();// 创建 CGLIB 代理对象DeviceMessageInterface proxyInstance = createCglibProxy(instance.getClass(), beanName);// 调用 sendMessage 方法JSONObject jsonObject = proxyInstance.receiveMessage(taskvo);return jsonObject;}} catch (Exception e) {e.printStackTrace();}JSONObject jsonObject = new JSONObject();try{jsonObject.put("msg", "信息异常");}catch (JSONException ex){}return jsonObject;}public <T> T createCglibProxy(Class<T> targetClass, String beanName) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(targetClass);enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("Before method: " + method.getName());Object result = proxy.invokeSuper(obj, args);System.out.println("After method: " + method.getName());return result;}});T proxyInstance = (T) enhancer.create();autowireCapableBeanFactory.autowireBean(proxyInstance);return proxyInstance;}}

相关文章:

Spring boot 项目 Spring 注入 代理 并支持 代理对象使用 @Autowired 去调用其他服务

文章目录 类定义与依赖注入方法解析createCglibProxy注意事项setApplicationContext 方法createCglibProxy 方法 类定义与依赖注入 Service: 标识这是一个 Spring 管理的服务类。ApplicationContextAware: 实现该接口允许你在类中获取 ApplicationContext 对象&#xff0c;从而…...

Colyseus 与 HTTP API 的集成

Colyseus 与 HTTP API 的集成 在使用 Colyseus 开发实时多人应用时&#xff0c;通常需要与传统的 HTTP API 集成&#xff0c;例如用户身份验证、存储游戏数据、获取排行榜等。以下是 Colyseus 与 HTTP API 集成的详细介绍&#xff1a; 1. Colyseus 的基本架构 Colyseus 是一个…...

基于服务器部署的综合视频安防系统的智慧快消开源了。

智慧快消视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。国产化人工智能“…...

SpringBoot原理分析-1

SpringBoot原理分析 作为一个javaer&#xff0c;和boot打交道是很常见的吧。熟悉boot的人都会知道&#xff0c;启动一个springboot应用&#xff0c;就是用鼠标点一下启动main方法&#xff0c;然后等着就行了。我们来看看这个main里面。 SpringBootApplication public class E…...

HCIA-Access V2.5_7_5_XG(S)- GPON网络演进为XG(S)-PON网络

目前由于10 GPON ONU数量并没有得到大规模爆发,所以直接新建ODN网络成本相对较高,所以可以采用复用ODN的方案。 XG(S)-PON可以与GPON共享ODN 前面也介绍过GPON和10G GPON使用的波长,我们来回顾一下,在GPON网络中上行采用1310纳米波长,下行采用1490纳米的波长,而10G GPON…...

GPU算力平台的应用之任意门:任意穿搭匹配模型的应用教程

大家好&#xff0c;今天给大家介绍一下&#xff1a;GPU算力平台的应用之任意门:任意穿搭匹配模型的应用教程。 文章目录 一、GPU算力平台概述人工智能智能发展为什么需要GPU算力平台 二、注册与登录账号注册流程 三、平台的应用之Anydoor应用启动器选择Anydoor的应用场景Anydoo…...

如何利用人工智能算法优化知识分类和标签?

如何利用人工智能算法优化知识分类和标签&#xff1f; 聚类算法 原理与应用&#xff1a; 聚类算法是一种无监督学习算法&#xff0c;它可以根据数据的相似性将知识内容自动划分成不同的类别。例如&#xff0c;在文档知识库中&#xff0c;通过对文档内容的词向量表示应用 K -…...

Windows 11 系统中npm-cache优化

在 Windows 11 系统中&#xff0c;C:\Users\K\AppData\Local\npm-cache 文件夹是 npm&#xff08;Node Package Manager&#xff09; 用于缓存已下载的包的目录。缓存的存在可以加快包的安装速度&#xff0c;因为当再次安装相同的包时&#xff0c;npm 可以直接从缓存中获取&…...

Flink使用

Window下启动支持 下载或复制老版本的放在bin目录下即可&#xff1b; flink.bat echo off setlocalSET bin%~dp0 SET FLINK_HOME%bin%.. SET FLINK_LIB_DIR%FLINK_HOME%\lib SET FLINK_PLUGINS_DIR%FLINK_HOME%\pluginsSET JVM_ARGS-Xmx512mSET FLINK_JM_CLASSPATH%FLINK_LI…...

简易屏幕共享工具-基于WebSocket

前面写了两个简单的屏幕共享工具&#xff0c;不过那只是为了验证通过截屏的方式是否可行&#xff0c;因为通常手动截屏的频率很低&#xff0c;而对于视频来说它的帧率要求就很高了&#xff0c;至少要一秒30帧率左右。所以&#xff0c;经过实际的截屏工具验证&#xff0c;我了解…...

Redis——主从复制模式

文章目录 1. 引入2. 主从复制模式2.1 概念2.2 配置2.3 原理2.3.1 建立连接阶段2.3.2 命令传播阶段2.3.3 心跳检测机制2.3.4 部分重同步机制(1) 主节点通过 复制积压缓冲区 记录写命令(2) 主节点通过 复制偏移量 判断从节点是否满足执行部分重同步的条件(3) 执行部分重同步操作 …...

简历_熟悉缓存高并发场景处理方法,如缓存穿透、缓存击穿、缓存雪崩

系列博客目录 文章目录 系列博客目录1.缓存穿透总结 2.缓存雪崩3.缓存击穿代码总结 1.缓存穿透 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;这些请求都会打到数据库。 常见的解决方案有两种&#xff1a; 缓存空对…...

阿里云电商平台用户行为分析与人群画像系统设计与实现

通过在阿里云&#xff08;https://baike.baidu.com/item/%E9%98%BF%E9%87%8C%E4%BA%91/297128&#xff09;上构建包含数据源层、数据存储层、数据处理层、数据分析层和数据应用层的系统架构&#xff0c;并设计合理的数据模型、ETL流程、数据质量与性能监控机制以及安全与合规性…...

Go语言的 的输入/输出流(I/O Streams)核心知识

Go语言的输入/输出流&#xff08;I/O Streams&#xff09;核心知识 前言 Go语言是一种现代编程语言&#xff0c;因其高效性、简洁性及强大的并发支持而受到开发者的喜爱。在开发应用程序时&#xff0c;输入/输出&#xff08;I/O&#xff09;操作是一个不可或缺的部分。无论是…...

57.在 Vue 3 中使用 OpenLayers 点击选择 Feature 设置特定颜色

在 Web 开发中&#xff0c;地图应用是非常常见的需求&#xff0c;而 OpenLayers 是一个非常强大的地图库&#xff0c;它提供了丰富的地图操作功能。今天&#xff0c;我们将一起学习如何在 Vue 3 中结合 OpenLayers 使用点击事件来选择地图上的 Feature&#xff0c;并设置特定的…...

数据结构C语言描述8(图文结合)--哈希、哈希冲突、开放地址法、链地址法等实现

前言 这个专栏将会用纯C实现常用的数据结构和简单的算法&#xff1b;有C基础即可跟着学习&#xff0c;代码均可运行&#xff1b;准备考研的也可跟着写&#xff0c;个人感觉&#xff0c;如果时间充裕&#xff0c;手写一遍比看书、刷题管用很多&#xff0c;这也是本人采用纯C语言…...

自动化立体库安全使用管理制度完整版

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。欢迎大家到本文底部评论区留言。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载。 以下是《…...

云打印之拼多多打印组件交互协议

拼多多打印组件交互协议相关介绍如下&#xff1a; 1、打印组件下载地址 http://meta.pinduoduo.com/api/one/app/v1/lateststable?appIdcom.xunmeng.pddprint&platformwindows&subTypemain 2、socket连接端口 如果是http的话&#xff0c;端口是5000 socket new …...

TCP 演进之路:软硬件跷跷板与新征程

今天依旧是与 TCP 相关的一个短评。 先看软硬件间的胶着。晶体管诞生以来&#xff0c;硬件一直在突飞猛进发展&#xff0c;后来这个事被摩尔定律正则化&#xff0c;人们开始可以预测未来&#xff0c;但即便如此&#xff0c;软件依然跟不上来&#xff0c;不过几年&#xff0c;老…...

React最小状态管理Jotai

Jotai 状态管理 1. 简介 Jotai 是一个基于原子 atom 概念的 React 状态管理库&#xff0c;它提供了简单且灵活的方式来管理应用状态, 而且非常轻量&#xff0c; 大厂用的非常多。 JotaiRedux适合单个页面&#xff0c;多次用到的属性适合全局公共属性超级轻量&#xff08;与use…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

【项目实战】通过多模态+LangGraph实现PPT生成助手

PPT自动生成系统 基于LangGraph的PPT自动生成系统&#xff0c;可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析&#xff1a;自动解析Markdown文档结构PPT模板分析&#xff1a;分析PPT模板的布局和风格智能布局决策&#xff1a;匹配内容与合适的PPT布局自动…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

三体问题详解

从物理学角度&#xff0c;三体问题之所以不稳定&#xff0c;是因为三个天体在万有引力作用下相互作用&#xff0c;形成一个非线性耦合系统。我们可以从牛顿经典力学出发&#xff0c;列出具体的运动方程&#xff0c;并说明为何这个系统本质上是混沌的&#xff0c;无法得到一般解…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...