SpringBoot(三十)Springboot使用CGLIB动态代理

在Spring Boot中,使用CGLIB进行动态代理通常是为了创建目标类的代理对象,以便在不修改原始代码的情况下增加额外的行为。

比如增加方法的日志记录、性能监控、事务管理等。

以下是一个使用CGLIB动态代理的简单示例:

不需要添加任何依赖,Springboot默认的动态代理就是CGLIB。

一:创建一个需要被代理的类:

CGLIB动态代理不需要类一定要实现接口,所以我这里直接创建一个类即可,当然,你要想先创建接口,在做一个实现类也是可以的。看你自己的习惯。

typescript 复制代码
package com.modules.controller.test;

public class IndexImpl
{
    public void test(int num,String search)
    {
        System.out.println("num:" + num);
        System.out.println("search:" + search);
        System.out.println("进入了IndexImpl中的test方法!");
    }

    public String sayHello(String name)
    {
        return "Hello, " + name + "!";
    }
}

二:使用CGLIB创建代理类:

这个就没什么好讲的了,跟我们代理模式里边讲的是一样的,里边有注释。参照即可。

kotlin 复制代码
package com.modules.controller.fontend;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.Arrays;

public class CglibProxy implements MethodInterceptor {

    private Object target;

    /**
     * CGLIB动态代理类
     */

    public Object getProxyObject(Object target)
    {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    /**
     * 代理对象执行的所有方法都会走这个方法
     *
     * @param object           被代理的对象
     * @param method      被代理对象需要执行的方法
     * @param args     被代理对象需要执行的方法 参数
     * @param proxy 触发父类的方法对象
     * @return 被代理对象需要执行的方法 返回值
     * @throws Throwable 抛出的异常信息
     */
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable
    {
        System.out.println("Before method execution: " + method.getName());
        System.out.println(Arrays.stream(args).iterator().next().getClass().getName());
        System.out.println(proxy.getSuperIndex());
        System.out.println(proxy.getSuperName());
        System.out.println(proxy.getSignature().getName());
        System.out.println("After method execution: " + method.getName());

        System.out.println("Before method execution: " + method.getName());
        Object result = proxy.invokeSuper(object, args);
        System.out.println("After method execution: " + method.getName());
        return result;
    }
}

三:使用代理类:

测试一下:

ini 复制代码
public static void main(String[] args)
{
    CglibProxy cglibProxy = new CglibProxy();
    // 获取代理对象
    IndexImpl proxyIndexService = (IndexImpl) cglibProxy.getProxyObject(new IndexImpl());
    // 执行代理方法
    proxyIndexService.test(1,"");

    IndexImpl proxyHelloService = (IndexImpl) cglibProxy.getProxyObject(new IndexImpl());
    String result = proxyHelloService.sayHello("World");
    System.out.println(result);
}

运行代码,控制台输出:

bash 复制代码
Before method execution: test
java.lang.Integer
15
CGLIB$test$0
test
After method execution: test
Before method execution: test
num:1
search:
进入了IndexImpl中的test方法!
After method execution: test
Before method execution: sayHello
java.lang.String
12
CGLIB$sayHello$1
sayHello
After method execution: sayHello
Before method execution: sayHello
After method execution: sayHello
Hello, World!

在这个例子中,CglibProxy类实现了MethodInterceptor接口,并重写了intercept方法。当你调用代理对象的方法时,intercept方法会被调用,并在其中可以添加自定义的逻辑。在getProxyObject方法中,我们使用Enhancer来创建代理对象。

以上代码仅作为使用CGLIB的简单示例,实际项目中可能需要更复杂的逻辑处理。

四:CGLIB优缺点:

1.优点

JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLb了。

另一个优点是Cglib动态代理比使用java反射的JDK动态代理要快(Cglib的FastClass机制)。

2.缺点

对于被代理类中的final方法,无法进行代理,因为子类中无法重写final函数。

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLIB在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之,使用JDK方式要更为合适一些。

同时,由于CGLIB由于是采用动态创建子类的方法,对于final方法,无法进行代理。

以上大概就是Springboot使用CGLIB动态代理的基本方式。

有好的建议,请在下方输入你的评论

相关推荐
程序猿DD3 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
蛋蛋的就会顺顺的5 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
余槐i5 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8266 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡6 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
凤山老林7 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne8 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF8 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
silvamux_8 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
pride.li9 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉