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动态代理的基本方式。

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

相关推荐
一只叫煤球的猫34 分钟前
ThreadForge 源码解读一:ThreadScope 如何把并发任务放进清晰边界?
java·面试·开源
皮皮林55142 分钟前
@Autowired 和 @Resource 注解有啥区别?你这项目怎么还混着用呢?
后端
洛_尘1 小时前
Python 5:使用库
java·前端·python
程序员小假1 小时前
HTTP3 性能更好,为什么内网微服务依然多用 HTTP2?HTTP2 内网优势是什么?
java·后端
Mr数据杨1 小时前
【Codex】用教案主体模块沉淀标准化教学设计内容
java·开发语言·django·codex·项目开发
wangbing11252 小时前
踩坑:el8应用装在el9上
开发语言·后端·ruby
苍煜2 小时前
RocketMQ系列第三篇:Java原生基础使用实操,手把手写生产者消费者Demo
java·rocketmq·java-rocketmq
Andya_net2 小时前
Java | Java内存模型JMM
java·开发语言
182******20832 小时前
2026年java后端还有机会吗?还能找到工作吗?
java·开发语言
kyriewen113 小时前
你等的Babel编译,够喝三杯咖啡了——用Rust重写的SWC,只需眨个眼
开发语言·前端·javascript·后端·性能优化·rust·前端框架