Spring CGLlB动态代理
通过学习《Spring JDK动态代理》一节可以了解到,JDK 动态代理使用起来非常简单,但是 JDK 动态代理的目标类必须要实现一个或多个接口,具有一定的局限性。如果不希望实现接口,可以使用 CGLIB代理。
CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它被许多
AOP 框架所使用,其底层是通过使用一个小而快的字节码处理框架 ASM(Java 字节码操控框架)转换字节码并生成新的类。使用 CGLIB
需要导入 CGLIB 和 ASM 包,即 asm-x.x.jar 和 CGLIB-x.x.x.jar 。如果您已经导入了 Spring 的核心包
spring-core-x.x.x.RELEASE.jar,就不用再导入 asm-x.x.jar 和 cglib-x.x.x.jar 了。
Spring 核心包中包含 CGLIB 和 asm,也就是说 Spring 核心包已经集成了 CGLIB 所需要的包,所以在开发中不需要另外导入asm-x.x.jar 和 cglib-x.x.x.jar 包了。
示例
下面使用 Eclipse IDE 演示 CGLIB 动态代理的使用,步骤如下:
- 创建 SpringDemo 项目,并在 src 目录下创建 net.biancheng 包。
- 导入相关 JAR 包。
- 在 net.biancheng 包下创建 UserManager(用户管理接口)、UserManagerImpl(用户管理接口实现类)、MyAspect(切面类)和 CGLIBProxy(动态代理类)。
- 运行 SpringDemo 项目。
UserManager 类代码如下。
package net.biancheng; public interface UserManager { // 新增用户抽象方法 void addUser(String userName, String password); // 删除用户抽象方法 void delUser(String userName); }
UserManagerImpl 类代码如下。
package net.biancheng; public class UserManagerImpl implements UserManager { @Override public void addUser(String userName, String password) { System.out.println("正在执行添加用户方法"); System.out.println("用户名称: " + userName + " 密码: " + password); } @Override public void delUser(String userName) { System.out.println("正在执行删除用户方法"); System.out.println("用户名称: " + userName); } }
MyAspect 类代码如下。
package net.biancheng; public class MyAspect { public void myBefore() { System.out.println("方法执行之前"); } public void myAfter() { System.out.println("方法执行之后"); } }
CglibProxy 类代码如下。
package net.biancheng; import java.lang.reflect.Method; import org.springframework.CGLIB.proxy.Enhancer; import org.springframework.CGLIB.proxy.MethodInterceptor; import org.springframework.CGLIB.proxy.MethodProxy; /** * CGLIB动态代理,实现MethodInterceptor接口 * * @author 编程帮 * */ public class CglibProxy implements MethodInterceptor { private Object target;// 需要代理的目标对象 final MyAspect myAspect = new MyAspect(); // 重写拦截方法 @Override public Object intercept(Object obj, Method method, Object[] arr, MethodProxy proxy) throws Throwable { myAspect.myBefore(); Object invoke = method.invoke(target, arr);// 方法执行,参数:target目标对象 arr参数数组 myAspect.myAfter(); return invoke; } // 定义获取代理对象方法 public Object getCglibProxy(Object objectTarget) { // 为目标对象target赋值 this.target = objectTarget; Enhancer enhancer = new Enhancer(); // 设置父类,因为CGLIB是针对指定的类生成一个子类,所以需要指定父类 enhancer.setSuperclass(objectTarget.getClass()); enhancer.setCallback(this);// 设置回调 Object result = enhancer.create();// 创建并返回代理对象 return result; } public static void main(String[] args) { CglibProxy cglib= new CglibProxy();// 实例化CglibBProxy对象 UserManager user = (UserManager) cglib.getCglibProxy(new UserManagerImpl());// 获取代理对象 user.addUser("bianchengbang", "www.biancheng.net"); // 执行新增方法 user.delUser("bianchengbang"); // 执行删除方法 } }
运行结果如下。
方法执行之前
正在执行添加用户方法
用户名称: bianchengbang 密码: www.biancheng.net
方法执行之后
方法执行之前
正在执行删除用户方法
用户名称: bianchengbang
方法执行之后
JDK代理和CGLIB代理的区别
JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 InvokeHandler 来处理。而 CGLIB 动态代理是利用 ASM 开源包,加载代理对象类的 class 文件,通过修改其字节码生成子类来处理。
JDK 动态代理只能对实现了接口的类生成代理,而不能针对类。
CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法不能声明成 final 类型。
JDK动态代理特点
- 代理对象必须实现一个或多个接口
- 以接口的形式接收代理实例,而不是代理类
CGLIB动态代理特点
- 代理对象不能被 final 修饰
- 以类或接口形式接收代理实例
JDK与CGLIB动态代理的性能比较
生成代理实例性能:JDK > CGLIB
代理实例运行性能:JDK > CGLIB
http://c.biancheng.net/spring/cglib-proxy.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
2019-08-16 为Endnote中的期刊名称添加缩写期刊名
2017-08-16 qvalue: Check that you have valid p-values or use a different range of lambda
2014-08-16 mysql 字符串函数
2011-08-16 WinRAR命令行参数
2011-08-16 水平集方法 level set method
2011-08-16 基底膜(basement membrane, BM)
2011-08-16 肿瘤基础知识