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

文章目录

类定义与依赖注入

  • @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。

java 复制代码
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;
}
java 复制代码
public <T> T createCglibProxy(Class<T> targetClass, String beanName) {

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

参数:

  • targetClass: 目标类的 Class 对象,用于指定要代理的类。
  • beanName: 字符串类型的参数,代表目标 Bean 的名称(虽然在这个方法中没有直接使用)。
java 复制代码
Enhancer enhancer = new Enhancer();
  • 创建 CGLIB 的 Enhancer 实例:Enhancer 是 CGLIB 中用来生成子类或代理类的核心类。
java 复制代码
enhancer.setSuperclass(targetClass);
  • 设置父类:告诉 Enhancer 使用 targetClass 作为代理类的父类。这意味着代理类将继承 targetClass 的所有非私有方法。
java 复制代码
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) 调用了原始类的方法实现。
    • 返回结果:将原始方法的结果返回给调用者。
java 复制代码
T proxyInstance = (T) enhancer.create();
  • 创建代理实例:enhancer.create() 方法根据配置创建并返回一个新的代理实例。这里强制转换为 T 类型,确保返回值与输入参数 targetClass 的类型一致。
java 复制代码
autowireCapableBeanFactory.autowireBean(proxyInstance);
  • 自动装配依赖:使用 Spring 的 AutowireCapableBeanFactory 对代理实例进行自动装配,这一步骤使得代理对象能够像普通的 Spring Bean 一样获得依赖注入。

    return proxyInstance;

  • 返回代理对象:最终返回创建好的代理对象,供调用方使用。

java 复制代码
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;
    }

}
相关推荐
东方小月15 分钟前
NestJS中如何优雅的实现接口日志记录
前端·后端·nestjs
蔚蓝的珊瑚海_xdcaxy201317 分钟前
Flask返回浏览器无乱码方法
后端·python·flask
java熊猫28 分钟前
Lua语言的多线程编程
开发语言·后端·golang
JINGWHALE11 小时前
设计模式 行为型 策略模式(Strategy Pattern)与 常见技术框架应用 解析
前端·人工智能·后端·设计模式·性能优化·系统架构·策略模式
Java白菜治1 小时前
Java后端常用的4种请求方式(通俗易懂)
java·网络·spring boot·http
raoxiaoya1 小时前
golang中的迭代器和 iter 包
开发语言·后端·golang
思无邪66751 小时前
关于重构一点简单想法
后端
栗筝i2 小时前
Spring 核心技术解析【纯干货版】- V:Spring 基础模块 Spring-Context 模块精讲
java·数据库·spring
C++小厨神2 小时前
Go语言的字符串处理
开发语言·后端·golang
m0_748236112 小时前
芋道源码(无遮羞布版)Spring Boot 全景指南
java·spring boot·后端