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() {
        @Override
        public 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() {
    @Override
    public 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;

    @Autowired
    private AutowireCapableBeanFactory autowireCapableBeanFactory;

//    @Autowired
//    private ThreadPoolTaskExecutor taskExecutor;

    private CountDownLatch countDownLatch;

    @Override
    public 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 的 Bean
            Map<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 的 Bean
            Map<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() {
            @Override
            public 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;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/948739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

应用程序越权漏洞安全测试总结体会

应用程序越权漏洞安全测试总结体会 一、 越权漏洞简介 越权漏洞顾名思议超越了自身的权限去访问一些资源&#xff0c;在OWASP TOP10 2021中归类为A01&#xff1a;Broken Access Control&#xff0c;其本质原因为对访问用户的权限未进行校验或者校验不严谨。在一个特定的系统或…

JAVA:Spring Boot 集成 Quartz 实现分布式任务的技术指南

1、简述 Quartz 是一个强大的任务调度框架&#xff0c;允许开发者在应用程序中定义和执行定时任务。在 Spring Boot 中集成 Quartz&#xff0c;可以轻松实现任务的调度、管理、暂停和恢复等功能。在分布式系统中&#xff0c;Quartz 也支持集群化的任务调度&#xff0c;确保任务…

改善 Kibana 中的 ES|QL 编辑器体验

作者&#xff1a;来自 Elastic Marco Liberati 随着新的 ES|QL 语言正式发布&#xff0c;Kibana 中开发了一种新的编辑器体验&#xff0c;以帮助用户编写更快、更好的查询。实时验证、改进的自动完成和快速修复等功能将简化 ES|QL 体验。 我们将介绍改进 Kibana 中 ES|QL 编辑器…

【深度学习入门_基础篇】线性代数本质

开坑本部分主要为基础知识复习&#xff0c;新开坑中&#xff0c;学习记录自用。 学习目标&#xff1a; 熟悉向量、线性组合、线性变换、基变换、矩阵运算、逆函数、秩、列空间、零空间、范式、特征指、特征向量等含义与应用。 强烈推荐此视频&#xff1a; 【官方双语/合集】…

【SpringBoot】当 @PathVariable 遇到 /,如何处理

1. 问题复现 在解析一个 URL 时&#xff0c;我们经常会使用 PathVariable 这个注解。例如我们会经常见到如下风格的代码&#xff1a; RestController Slf4j public class HelloWorldController {RequestMapping(path "/hi1/{name}", method RequestMethod.GET)publ…

VBA(Visual Basic for Applications)编程|excel|一系列网址或文件路径快速转换为可点击的超链接

很多时候&#xff0c;我们需要把导入的数据某一列转换成超链接&#xff0c;比如URL形式的列。 那么&#xff0c;大批量的情况下&#xff0c;无疑一个个手动点击是非常愚蠢的办法&#xff0c;这个时候我们就需要VBA编程来编写宏&#xff0c;通过编写宏来简化这些手动操作并不现…

小程序开发全解析 快速构建高效应用的核心指南

内容概要 小程序开发是当前数字世界中炙手可热的领域&#xff0c;吸引了无数开发者和企业的关注。随着技术的进步&#xff0c;小程序成为了提升用户体验、增强品牌曝光以及增加客户互动的重要工具。了解小程序的基本概念&#xff0c;就像是打开了一扇通往新世界的大门。 在这…

SQL—Group_Concat函数用法详解

SQL—Group_Concat函数用法详解 在LC遇见的一道很有趣的SQL题&#xff0c;有用到这个函数&#xff0c;就借这道题抛砖引玉&#xff0c;在此讲解一下group_concat函数的用法。&#x1f923; GROUP_CONCAT([DISTINCT] expression [ORDER BY expression] [SEPARATOR separator])…

Edge Scdn的应用场景有哪些?

酷盾安全Edge Scdn 具备强大的安全防护能力&#xff0c;通过多层防御机制&#xff0c;如防火墙、DDoS 攻击防护、入侵检测和防御、数据加密等&#xff0c;有效抵御各种网络攻击&#xff0c;包括 DDoS 攻击、CC 攻击、SQL 注入攻击、XSS 跨站脚本攻击等&#xff0c;保障网站和应…

流光效果

1、流光效果是什么 在 Unity Shader 中的流光效果是一种动态的视觉效果&#xff0c;通常用于给材质增加一种闪光或光线移动的效果&#xff0c;使物体表面看起来像是有光在流动。这种效果常用于武器光效、能量护盾、传送门等等&#xff0c;可以让物体看起来更加生动富有科技感 …

滑动窗口——串联所有单词的子串

一.题目描述 30. 串联所有单词的子串 - 力扣&#xff08;LeetCode&#xff09; 二.题目解析 题目前提&#xff1a;s是一个字符串&#xff0c;words是一个字符串数组&#xff0c;里面所有的字符串的长度都是相等的。 题目要求&#xff1a;找到s中的一段连续的子串&#xff0…

【微软,模型规模】模型参数规模泄露:理解大型语言模型的参数量级

模型参数规模泄露&#xff1a;理解大型语言模型的参数量级 关键词&#xff1a; #大型语言模型 Large Language Model #参数规模 Parameter Scale #GPT-4o #GPT-4o-mini #Claude 3.5 Sonnet 具体实例与推演 近日&#xff0c;微软在一篇医学相关论文中意外泄露了OpenAI及Claud…

SpringBoot Maven 项目 pom 中的 plugin 插件用法整理

把 SpringBoot Maven 项目打包成 jar 文件时&#xff0c;我们通常用到 spring-boot-maven-plugin 插件。 前面也介绍过&#xff0c;在 spring-boot-starter-parent POM 和 spring-boot-starter POM 中都有插件的管理&#xff0c;现在我们就撸一把构建元素中插件的用法。 一、…

UE5AI感知组件

官方解释&#xff1a; AI感知系统为Pawn提供了一种从环境中接收数据的方式&#xff0c;例如噪音的来源、AI是否遭到破坏、或AI是否看到了什么。 AI感知组件&#xff08;AIPerception Component&#xff09;是用于实现游戏中的非玩家角色&#xff08;NPC&#xff09;对环境和其…

【数据仓库】hive on Tez配置

hive on Tez 搭建 前提是hive4.0hadoop3.2.2数仓已搭建完成&#xff0c;现在只是更换其执行引擎 为Tez。搭建可参考【数据仓库】hive hadoop数仓搭建实践文章。 Tez 下载 下载地址 https://archive.apache.org/dist/tez/ 官网地址 https://tez.apache.org/releases/apac…

finereport动态数据源插件教程2

场景&#xff1a; 模板中有多个数据集&#xff0c;只需要其中一个数据集按照不同的参数显示不同数据库的数据。 模板制作&#xff1a; 两个数据集ds1&#xff0c;ds2&#xff0c;ds1的绑定到参数面板的下拉框上&#xff0c;ds2显示到模板正文中&#xff0c;现在需要ds1根据不同…

Java通过谷歌邮箱Gmail直接发送邮件的三种方式

错误 Connected to the target VM, address: 127.0.0.1:52082, transport: socketException in thread "main" javax.mail.MessagingException: Got bad greeting from SMTP host: smtp.gmail.com, port: 587, response: [EOF] at com.sun.mail.smtp.SMTPTransp…

WSDM 2025 | 时间序列(time series)论文总结

AWSDM 2025于2025年3月10号到14号在德国汉诺威举行&#xff08;Hannover, Germany&#xff09; 本文总结了WSDM 2024有关时间序列&#xff08;time series&#xff09;的相关论文&#xff0c;如有疏漏&#xff0c;欢迎大家补充。&#xff08;没有时空数据相关的论文&#xff0…

反直觉导致卡关-迫击炮谜题

这个谜题&#xff0c;在两周目中先后卡了我至少三个小时&#xff0c;先后缓慢装填并发射迫击炮弹尝试了数百次。 一周目卡了很久&#xff0c;稀里糊涂的过了&#xff0c;想不到二周目还会卡那么久。 研究了很多播主的攻略&#xff0c;但还是一头雾水&#xff0c; 直到分析其…

庐山派K230学习日记4 PWM控制

1 本节介绍​ &#x1f4dd;本节您将学习如何通过将K230开发板的GPIO引脚复用为PWM功能并输出PWM信号&#xff1b;实现输出PWM信号及控制板载无源蜂鸣器发出声音。 &#x1f3c6;学习目标 1️⃣如何将GPIO引脚配置为PWM模式&#xff0c;通过40Pin排针中的部分引脚来输出PWM信号…