关于cglib:CGLIB动态代理底层实现原理

一、前言  最近在探索Spring AOP的性能,发现最初是绕不开JDK动静代理和CGLIB动静代理这两个点。笔者心里大抵有这么个概念:对于动静代理来说,CGLIB性能要好于JDK。也晓得CGLIB是利用ASM技术基于继承子类实现动静代理,JDK是基于实现接口实现动静代理,然而对于底层实现还是比拟含糊。明天就彻底整明确CGLIB动静代理的底层实现。 二、前置筹备(一)测试代码CGLIB外围的几个概念: 被代理对象,本案例【Dog】办法拦截器MethodInterceptor,本案例【CglibMethodInterceptor】Enhance代理对象生成工具,本案例【TestMain测试主类中创立】1. 自定义办法拦截器CglibMethodInterceptor  前面也会将MethodInterceptor说成Callback,其实是一个货色,MethodInterceptor是实现了Callback接口的。 /** * 办法拦截器,不必依赖被代理业务类的援用 */public class CglibMethodInterceptor implements MethodInterceptor { /** * 性能次要是在调用业务类办法之前 之后增加统计工夫的办法逻辑. * intercept 因为具备 MethodProxy methodProxy 参数的起因,不再须要代理类的援用对象了,间接通过 methodProxy 对象拜访被代理对象的办法(这种形式更快)。 * 当然 也能够通过反射机制,通过 method 援用实例 Object result = method.invoke(target, args); 模式反射调用被代理类办法, * target 实例代表被代理类对象援用, 初始化 CglibMethodInterceptor 时候被赋值 。然而Cglib不举荐应用这种形式 * * @param object 代表Cglib 生成的动静代理类 对象自身 * @param method 代理类中被拦挡的接口办法 Method 实例 * @param args 接口办法参数 * @param methodProxy 用于调用父类真正的业务类办法。能够间接调用被代理类接口办法 * @return 被代理类办法执行返回值 * @throws Throwable */ @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("before"); MonitorUtil.start(); Object result = methodProxy.invokeSuper(object, args);// Object result = methodProxy.invoke(object, args); System.out.println("after"); MonitorUtil.finish(method.getName()); return result; }}2. 被代理类public class Dog { public String call() { System.out.println("wang wang wang"); return "Dog .."; } }3. 切面办法/** * 办法用时监控类,作为一个切面 ,具备两个办法 */public class MonitorUtil { private static final ThreadLocal<Long> tl = new ThreadLocal<>(); public static void start() { tl.set(System.currentTimeMillis()); } /** * 完结时打印耗时 * @param methodName 监控办法名 */ public static void finish(String methodName) { long finishTime = System.currentTimeMillis(); System.out.println(methodName + "办法执行耗时" + (finishTime - tl.get()) + "ms"); }}4. 测试主类public class TestMain { /** * 用于生成 Cglib 动静代理类工具办法 * @param target 代表须要 被代理的 委托类的 Class 对象 * @return 代理类对象 */ public static Object cglibProxyGenerator(Class target) { // 创立增强器,用来创立动静代理类 Enhancer enhancer = new Enhancer(); // 为代理类指定须要代理的类,也即是父类 enhancer.setSuperclass(target); // 设置办法拦截器回调援用,对于代理类上所有办法的调用,都会调用CallBack,而Callback则须要实现intercept() 办法进行拦挡 enhancer.setCallback(new CglibMethodInterceptor()); // 创立cglib 代理类 return enhancer.create(); } public static void main(String[] args) throws ClassNotFoundException { System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "classFiles"); Dog poolDog = (Dog) cglibProxyGenerator(Dog.class); poolDog.call(); }}(二)CGLIB生成的子类 Dog$$EnhancerByCGLIB$$beb9d601 ...

March 28, 2022 · 13 min · jiezi

java-什么是动态代理

微信公众号:一个优秀的废人。如有问题,请后台留言,反正我也不会听。最近在复习 Java 相关,回顾了下代理模式。代理模式在 Java 领域很多地方都有应用,它分为静态代理和动态代理,其中 Spring AOP 就是动态代理的典型例子。动态代理又分为接口代理和 cglib (子类代理),结合我的理解写了几个 demo 分享给你们,这是昨晚修仙到 3 点写出来的文章,不点在看,我觉得说不过去了。 代理模式在我们日常中很常见,生活处处有代理: 看张学友的演唱会很难抢票,可以找黄牛排队买嫌出去吃饭麻烦,可以叫外卖无论是黄牛、外卖骑手都得帮我们干活。但是他们不能一手包办(比如黄牛不能帮我吃饭),他们只能做我们不能或者不想做的事。 找黄牛可以帮我排队买上张学友的演唱会门票外卖骑手可以帮我把饭送到楼下所以,你看。代理模式其实就是当前对象不愿意做的事情,委托给别的对象做。 静态代理我还是以找黄牛帮我排队买张学友的演唱会门票的例子,写个 demo 说明。现在有一个 Human 接口,无论是我还是黄牛都实现了这个接口。 public interface Human { void eat(); void sleep(); void lookConcert();}例如,我这个类,我会吃饭和睡觉,如以下类: public class Me implements Human{ @Override public void eat() { System.out.println("eat emat ...."); } @Override public void sleep() { System.out.println("Go to bed at one o'clock in the morning"); } @Override public void lookConcert() { System.out.println("Listen to Jacky Cheung's Concert"); }}有黄牛类,例如: ...

May 12, 2019 · 4 min · jiezi

Cglib-和-Mica-Bean-copy-生成字节码对比

1. 前言距离上上篇【mica cglib 增强——【01】cglib bean copy 介绍】 已经过去一个月八一天。 距离上一篇【Java Bean Copy 性能大比拼】 已过去一个月零一天。 督促自己早日完成整个系列的文章,今天我将带领大家从字节码的层面来分析。 注:对于java 字节码感兴趣的朋友也可以阅读 《Java虚拟机规范》,Oracle 官方也有英文原版的 pdf可供下载。 2. Bean 模型我们列举2个模型 User 和 UserVo,注意:birthday 字段类型不一样(敲黑板)。 2.1 User@Datapublic class User { private Integer id; private String name; private Integer age; private LocalDateTime birthday;}2.2 UserVo@Datapublic class UserVo { private String name; private Integer age; private String birthday;} 3. Cglib Bean copy 字节码分析 3.1 配置 Cglib debug 模式在第一篇【mica cglib 增强——【01】cglib bean copy 介绍】我们提到可以设置 cglib 源码生成目录。 ...

April 30, 2019 · 3 min · jiezi

Spring boot 微服务核心组件集 mica v1.0.1 发布

mica(云母)mica 云母,寓意为云服务的核心,使得云服务开发更加方便快捷。mica 的前身是 lutool,lutool在内部孵化了小两年,已经被多个朋友运用到企业。由于 lutool 对微服务不够友好,故重塑了mica。mica 中的部分大部分组件进行了持续性打磨,增强易用性和性能。mica 核心依赖mica 基于 java 8,没有历史包袱,支持传统 Servlet 和 Reactive(webflux)。采用 mica-auto 自动生成 spring.factories 和 spring-devtools.properties 配置,仅依赖 Spring boot、Spring cloud 全家桶,无第三方依赖。市面上鲜有的微服务核心组件。更新说明[1.0.1] - 2019-04-03 处理几处 P3C 代码检查问题。@冷冷 优化泛型,避免部分环境下的编译问题。 添加 lutool 中的 WebUtil.renderJson()。 优化 DateUtil 性能。 优化 RuntimeUtil,提高性能。 升级 gradle 到 5.3.1。本次版本主要是进行了一些工具的压力测试:Bean copy 测试BenchmarkScoreErrorUnitshutool1939.09226.747ops/msspring3569.03539.607ops/mscglib9112.785560.503ops/msmica17753.409393.245ops/ms结论:mica 在非编译期 Bean copy 性能强劲,功能强大。UUID 压测BenchmarkScoreErrorUnitsjdk8UUId734.59517.220ops/msjdk8ThreadLocalRandomUUId3224.75932.107ops/mshutoolFastSimpleUUID3619.74867.195ops/msmicaUUId(java9 方式)12375.405241.879ops/ms结论:mica 在使用了 java9 的算法,性能卓越。Date format 压测BenchmarkScoreErrorUnitsjava8Date2405.92444.912ops/msmicaDateUtil2541.75348.321ops/mshutoolDateUtil2775.53113.526ops/ms结论:hutool 使用的 common lang3 的 FastDateFormat 占用优势。开源推荐mica Spring boot 微服务核心组件集:https://gitee.com/596392912/micaAvue 一款基于vue可配置化的神奇框架:https://gitee.com/smallweigit/avuepig 宇宙最强微服务(架构师必备):https://gitee.com/log4j/pigSpringBlade 完整的线上解决方案(企业开发必备):https://gitee.com/smallc/SpringBladeIJPay 支付SDK让支付触手可及:https://gitee.com/javen205/IJPay关注我们扫描上面二维码,更多精彩内容每天推荐!

April 4, 2019 · 1 min · jiezi

mica cglib 增强——[1]cglib bean copy 介绍

专栏介绍本套专栏主要是介绍微服务核心框架 Mica 中对 Cglib bean copy 的一系列增强,保证高性能的同时,提高易用性。整个专栏有 6 篇文章,感兴趣的朋友请加关注。专栏目录cglib bean copy 介绍。mica bean copy 介绍和链式 bean copy 的支持。mica bean 支持 copy 原始类型和封装类型。mica bean 支持 copy map 到 bean。使用Spring的类型转换增强 mica bean copy。mica bean、Map 互转增强和总结。Cglib BeanCopier 介绍阿里巴巴 p3c 插件中有这么一项检查 “避免用Apache Beanutils进行属性的copy,Apache BeanUtils性能较差,可以使用其他方案比如Spring BeanUtils, Cglib BeanCopier”。今天我们的主角主要就是 Cglib 的 BeanCopier。性能下图是 github 上的一个 Bean copy 性能的对比,可以看出 Bean copy 工具性能差距还是比较大。更多请见:https://github.com/yangtu222/BeanUtils#performance图中可以看出,Cglib BeanCopier 的性能十分强劲,也难怪阿里巴巴规范中也推荐,下面我们来看看它具体的使用方式。使用Cglib 以源码的形式纳入到 Spring core 中,所有大家使用 Spring、Spring boot 可以直接使用。其它则需要自己添加依赖,下面的使用例子都以 Spring 的为主。注意:使用了 Lombok 。User 对象@Datapublic class User { private Integer id; private String name; private Integer age;}UserVo 对象@Datapublic class UserVo { private String name; private Integer age;}Bean 拷贝import org.springframework.cglib.beans.BeanCopier;public class UserCopyTest { public static void main(String[] args) { // 1. 初始化 user,赋值 User user = new User(); user.setId(250); user.setName(“如梦技术”); user.setAge(30); // 2. 初始化 userVo UserVo userVo = new UserVo(); // 3. 构造 BeanCopier,不是用类型转换 BeanCopier copier = BeanCopier.create(User.class, UserVo.class, false); // 4. 拷贝对象,不是用类型转换,转换器可以使用 null copier.copy(user, userVo, null); // 5. 打印结果:UserVo(name=如梦技术, age=30) System.out.println(userVo); }}原理大家都知道 Cglib BeanCopier,之所以性能这么高主要是利用了 Asm 字节码技术。在 UserCopyTest 的 main 方法中添加下面的代码(建议直接放置到 1. 初始化 user,赋值 之前),指定cglib 源码生成目录,建议生成到 idea 项目中,可以直接打开生成的 class 字节码。// 设置 cglib 源码生成目录String sourcePath = “/Users/lcm/git/mica/mica-example/web-example/src/test/java”;System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, sourcePath);再次执行 main 方法。我们可以看到控制台打印下了这么一行日志。CGLIB debugging enabled, writing to ‘/Users/lcm/git/mica/mica-example/web-example/src/test/java’下面我们来看看生成的代码:看到此图大家恍然大悟,Cglib BeanCopier 帮我们生成了 get set 转换。Cglib copy 问题不支持链式 bean,mybatis-plus 生成的 Model 中默认添加了 @Accessors(chain = true) 注解默认为链式。不支持 原始类型和封装类型 copy int <-> Integer。类型转换不够智能,设置 useConverter 为 true 和重写 Converter,类型相同也会走转换的逻辑。注意:这部分后面会详细介绍,喜欢的朋友请关注、订阅我们。链接mica:https://github.com/lets-mica/mica如梦技术官网:https://www.dreamlu.net开源推荐Spring boot 微服务高效开发 mica 工具集:https://gitee.com/596392912/micaAvue 一款基于vue可配置化的神奇框架:https://gitee.com/smallweigit/avuepig 宇宙最强微服务(架构师必备):https://gitee.com/log4j/pigSpringBlade 完整的线上解决方案(企业开发必备):https://gitee.com/smallc/SpringBladeIJPay 支付SDK让支付触手可及:https://gitee.com/javen205/IJPay加入【如梦技术】Spring QQ群:479710041,了解更多。关注我们扫描上面二维码,更多精彩内容每天推荐! ...

March 26, 2019 · 1 min · jiezi