JDK动态代理 vs CGLIB:一场经纪人之战,谁才是你的最佳选择?咱今儿个来聊聊JDK动态代理和CGLIB代理,保证

发布时间:2025-07-03 03:26

微信图片_20250217112159.png

如果喜欢作者的讲解方式,关注作者不迷路,同时也可以看看我的其他文章! 感谢!!!

被重复代码逼疯?AOP来当“舔狗”!日志/事务/权限,随叫随到!

咱今儿个来聊聊JDK动态代理和CGLIB代理,保证你听得懂,记得住,还能用得上!

一、 啥是代理?为啥要有代理?(明星经纪人版)

想象一下,你是个超级巨星,每天行程排得满满当当,签合同、拍广告、跑通告,忙到飞起!你哪有时间事事亲力亲为?这时候,就需要一个经纪人来帮你打理一切!这个经纪人就是你的代理

代理:就是代替你去做一些事情的人或事物。就像你的经纪人,帮你处理各种琐事。 为啥要有代理? 解耦:明星不用直接面对各种烦人的事情,可以专心提升演技,唱好歌! 增强功能:经纪人可以帮你谈更高的片酬,安排更合理的行程,让你更火! 控制访问:经纪人可以帮你挡掉一些不必要的骚扰,保护你的隐私️!

在编程世界里,代理也是一样的道理!它可以让你在不修改原有代码的情况下,增强对象的功能,控制对象的访问。简直是程序员的福音!

二、 JDK动态代理:接口的守护者(接口明星的专属经纪人)

JDK动态代理,就像一个只服务于有接口的明星的经纪人。它要求你的明星(也就是你的类)必须有接口,才能为你保驾护航! JDK动态代理

原理:JDK动态代理是利用Java反射机制,在运行时动态地生成一个代理类。这个代理类实现了你的接口,并且可以拦截对接口方法的调用。就像经纪人时刻关注着你的行程,随时准备为你处理突发状况!

通俗易懂的解释

你定义一个接口,比如Star(明星)。就像你和经纪公司签的合同,规定了你的权利和义务。 你有一个实现了这个接口的类,比如RealStar(真正的明星)。你就是那个闪耀的明星!✨ 你创建一个InvocationHandler(经纪人),它知道如何处理对Star接口方法的调用。经纪人熟知你的所有行程,知道如何帮你处理各种事务。 通过Proxy.newProxyInstance()方法,JDK会动态地生成一个代理类,这个代理类也实现了Star接口。就像经纪公司为你配备了一个专属的代理人! 当你调用代理对象的sing()方法时,实际上是调用了InvocationHandler的invoke()方法。在这个方法里,你可以做一些额外的操作,比如记录日志、权限校验等等。经纪人会在你唱歌前后记录日志,确保一切顺利!

例子

简单例子:日志记录(经纪人帮你记录行程)

// 1. 定义接口 interface Star { void sing(String song); } // 2. 实现类 class RealStar implements Star { @Override public void sing(String song) { System.out.println("RealStar singing: " + song); } } // 3. InvocationHandler import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; class StarInvocationHandler implements InvocationHandler { private Object target; // 被代理的对象 public StarInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before singing, record the log."); // 增强功能:记录日志 Object result = method.invoke(target, args); // 调用真实对象的方法 System.out.println("After singing, record the log."); // 增强功能:记录日志 return result; } } // 4. 使用代理 import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { RealStar realStar = new RealStar(); StarInvocationHandler handler = new StarInvocationHandler(realStar); Star proxy = (Star) Proxy.newProxyInstance( realStar.getClass().getClassLoader(), //获取目标类对象的类加载器 realStar.getClass().getInterfaces(), //获取目标类对象实现的接口 handler //增强功能的类 ); proxy.sing("Hello World"); // 调用代理对象的方法 } } 稍微复杂点的例子:权限校验(经纪人帮你挡掉不必要的邀约)

// 假设有一个权限校验的接口 interface PermissionChecker { boolean hasPermission(String user, String operation); } // 实现类 class AdminPermissionChecker implements PermissionChecker { @Override public boolean hasPermission(String user, String operation) { // 模拟权限校验逻辑 if ("admin".equals(user) && "delete".equals(operation)) { return true; } return false; } } // 修改InvocationHandler import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; class StarInvocationHandler implements InvocationHandler { private Object target; private PermissionChecker permissionChecker; public StarInvocationHandler(Object target, PermissionChecker permissionChecker) { this.target = target; this.permissionChecker = permissionChecker; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 权限校验 if (method.getName().equals("sing")) { if (!permissionChecker.hasPermission("user", "sing")) { System.out.println("No permission to sing!"); return null; } } System.out.println("Before singing, record the log."); Object result = method.invoke(target, args); System.out.println("After singing, record the log."); return result; } } // 使用代理 import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { RealStar realStar = new RealStar(); AdminPermissionChecker permissionChecker = new AdminPermissionChecker(); StarInvocationHandler handler = new StarInvocationHandler(realStar, permissionChecker); Star proxy = (Star) Proxy.newProxyInstance( realStar.getClass().getClassLoader(), realStar.getClass().getInterfaces(), handler ); proxy.sing("Hello World"); // 调用代理对象的方法 } }

好处

简单易用,JDK自带,不需要引入额外的依赖。就像你天生自带光环!✨ 基于接口,符合面向接口编程的思想。就像你和经纪公司签的合同,一切按规矩办事!

缺点

只能代理实现了接口的类。如果你的类没有实现接口,就没法用JDK动态代理了。就像你没有和经纪公司签约,就没法享受经纪人的服务!

三、 CGLIB代理:类的守护者(全能经纪人)

CGLIB代理,就像一个更厉害的经纪人,它不需要你的明星有接口,直接就能代理你的类!简直是全能经纪人! CGLIB代理

原理:CGLIB(Code Generation Library)是一个强大的高性能的代码生成库。它通过生成目标类的子类来实现代理。就像经纪人直接接管了你的生活,为你安排一切!️

通俗易懂的解释

CGLIB会创建一个目标类的子类(代理类)。就像经纪人为你打造了一个全新的形象! 这个子类会重写目标类的方法。就像经纪人为你重新设计了你的表演风格! 当你调用代理对象的方法时,实际上是调用了子类重写后的方法。就像你按照经纪人的安排,进行表演! 在重写后的方法里,你可以做一些额外的操作,比如记录日志、权限校验等等。经纪人会在你表演前后记录日志,确保一切顺利!

例子(由易到难)

简单例子:日志记录(经纪人帮你记录行程)

// 1. 定义类(不需要接口) class Singer { public void sing(String song) { System.out.println("Singer singing: " + song); } } // 2. MethodInterceptor import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; class SingerMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before singing, record the log."); // 增强功能:记录日志 Object result = proxy.invokeSuper(obj, args); // 调用父类(目标类)的方法 System.out.println("After singing, record the log."); // 增强功能:记录日志 return result; } } // 3. 使用代理 import net.sf.cglib.proxy.Enhancer; public class Main { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Singer.class); // 设置父类(目标类) enhancer.setCallback(new SingerMethodInterceptor()); // 设置回调 Singer proxy = (Singer) enhancer.create(); // 创建代理对象 proxy.sing("Hello World"); // 调用代理对象的方法 } } 稍微复杂点的例子:性能监控(经纪人帮你分析表演效果)

// 1. 定义类(不需要接口) class Calculator { public int add(int a, int b) { return a + b; } } // 2. MethodInterceptor import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; class PerformanceMonitorInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { long startTime = System.nanoTime(); Object result = proxy.invokeSuper(obj, args); long endTime = System.nanoTime(); System.out.println(method.getName() + " execution time: " + (endTime - startTime) + " ns"); return result; } } // 3. 使用代理 import net.sf.cglib.proxy.Enhancer; public class Main { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Calculator.class); enhancer.setCallback(new PerformanceMonitorInterceptor()); Calculator proxy = (Calculator) enhancer.create(); proxy.add(1, 2); } }

好处

可以代理没有实现接口的类。即使你没有和经纪公司签约,也能找到全能经纪人为你服务!

缺点

需要引入额外的依赖(CGLIB库)。就像你需要支付经纪人一定的费用! CGLIB是通过生成子类来实现代理的,所以不能代理final类,因为final类不能被继承。就像你已经和别的经纪公司签约了,就不能再找别的经纪人了! CGLIB代理的效率相对JDK动态代理来说,稍微低一些(但通常可以忽略不计)。就像全能经纪人虽然厉害,但处理事情的速度可能稍微慢一点!

四、 JDK动态代理 vs CGLIB代理:谁更胜一筹?(经纪人PK)

特性JDK动态代理CGLIB代理接口要求必须实现接口不需要实现接口实现方式基于反射,动态生成代理类基于字节码生成,生成目标类的子类依赖JDK自带,无需额外依赖需要引入CGLIB库代理final类可以代理不能代理效率相对较高相对较低(但通常可以忽略不计)

总结

如果你的类实现了接口,优先选择JDK动态代理。就像你已经和经纪公司签约了,就优先选择经纪公司的服务! 如果你的类没有实现接口,只能选择CGLIB代理。就像你没有和经纪公司签约,只能找全能经纪人为你服务!

五、 在SpringBoot中,它们是如何应用的?(SpringBoot的智能经纪人系统)

在SpringBoot中,AOP(面向切面编程)是代理模式的典型应用场景。SpringBoot默认使用JDK动态代理,如果目标类没有实现接口,则会自动切换到CGLIB代理。就像SpringBoot有一个智能经纪人系统,会自动为你选择合适的经纪人!

例子:使用AOP记录方法执行时间(SpringBoot的智能经纪人帮你记录表演时间)

import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class TimeAspect { @Around("@annotation(com.example.demo.annotation.TimeLog)") // 拦截带有@TimeLog注解的方法 public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); Object proceed = joinPoint.proceed(); long executionTime = System.currentTimeMillis() - start; System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms"); return proceed; } }

import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface TimeLog { }

import org.springframework.stereotype.Service; @Service public class MyService { @TimeLog public void doSomething() { try { Thread.sleep(1000); // 模拟耗时操作 } catch (InterruptedException e) { e.printStackTrace(); } } }

在这个例子中,TimeAspect就是一个切面,它使用@Around注解来拦截带有@TimeLog注解的方法,并在方法执行前后记录时间。SpringBoot会自动使用代理模式来实现AOP,如果MyService实现了接口,则使用JDK动态代理,否则使用CGLIB代理。就像SpringBoot的智能经纪人系统会自动为你选择合适的经纪人,并帮你记录表演时间!⏱️

六、 总结

JDK动态代理和CGLIB代理都是代理模式的实现方式,它们可以让你在不修改原有代码的情况下,增强对象的功能,控制对象的访问。选择哪种代理方式,取决于你的类的具体情况。在SpringBoot中,AOP是代理模式的典型应用场景,SpringBoot会自动选择合适的代理方式来实现AOP。

希望这篇丰富、生动有趣的文章讲解能让你彻底理解JDK动态代理和CGLIB代理! 祝你早日成为编程界的超级巨星!

网址:JDK动态代理 vs CGLIB:一场经纪人之战,谁才是你的最佳选择?咱今儿个来聊聊JDK动态代理和CGLIB代理,保证 https://m.mxgxt.com/news/view/1534763

相关内容

动态代理:1 个经纪人如何代理 N 个明星
【SSM框架解析】——前篇:详解动态代理【案例驱动】(案例源码自取)
动态代理与反射1.动态代理 为什么需要代理? 假设你是个明星(BigStar),工作是唱歌、跳舞。但每次演出前,经纪人(
IDOL的代理模式
家人们,今天咱们来聊聊娱乐圈里...@唯冰秋之司的动态
嘿小伙伴们,今天咱们来聊聊一位曾经的...@丹丹的动态
各位小伙伴,今儿咱们得聊聊娱乐圈里...@小依依的动态
亲爱的朋友们,今天咱们来聊聊一个特...@柱严3的动态
今天来聊聊女明星的身材管理...@柠梦浅说娱乐的动态
Hey小伙伴们,今天咱们来聊聊关...@七七八八的动态

随便看看