Loading [MathJax]/jax/output/CommonHTML/jax.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >obligatory category_cglib为什么比jdk快

obligatory category_cglib为什么比jdk快

作者头像
全栈程序员站长
发布于 2022-10-29 02:25:13
发布于 2022-10-29 02:25:13
1.1K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

在一些系统代码中,随处可见的BeanCopier(源于org.springframework.cglib.beans),它主要用在将PO与DTO互转。一些人在惊叹它的高性能的同时,不曾了解它的实现原理(它不使用的反射)!它基于CGLIB代理,CGLIB(Code Generation Library)是高效的代码生成包,底层依靠ASM(开源的Java字节码编辑类库)操作字节码实现。

JDK动态代理与CGLIB代理

JDK动态代理,其被代理对象必须是某个接口的实现,它在运行期间生成代理对象,其实就是InvocationHandler,这个一点也不陌生。CGLIB代理,实现原理类似于JDK动态代理,也是在运行期间生成代理对象,但针对的被代理对象的要求不再那么严苛(不需要是某个接口的实现)。

多次强调运行期间生成代理对象?

难度还有非运行期间生成代理对象,是的,那就是编译期,之前讲过java冷知识:javac AbstractProcessor

生成后代理类究竟怎样的你知道么

BeanCopier.create会针对源类和目标类生成代理类(此处有反射),而且有一定时间上的消耗,但BeanCopier.copy并未使用反射。它正是巧妙的使用这点,将反射部分(性能差)部分与生成后硬编码分离!

CGLIB通过指定,System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, “target\\class”);

如何验证呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void copyRun() {
//输出cglib动态代理产生的类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "target\\class");
BeanCopier beanCopier = BeanCopier.create(CaiNiao.class, CainiaoDTO.class, false);
CaiNiao caiNiao = new CaiNiao();
caiNiao.setSuccess(true);
caiNiao.setErrorCode("suc");        
CainiaoDTO cainiaoDTO = new CainiaoDTO();        
beanCopier.copy(caiNiao,cainiaoDTO,null);
}
/**
* 最终会生成2个class文件
*/
//缓存的key
package org.springframework.cglib.beans;
public class BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a extends KeyFactory implements BeanCopierKey {
private final String FIELD_0;
private final String FIELD_1;
private final boolean FIELD_2;
public BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a() {
}
public Object newInstance(String var1, String var2, boolean var3) {
return new BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a(var1, var2, var3);
}
public BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a(String var1, String var2, boolean var3) {
this.FIELD_0 = var1;
this.FIELD_1 = var2;
this.FIELD_2 = var3;
}
public int hashCode() {
int var10002 = 95401 * 54189869;
String var10001 = this.FIELD_0;
var10002 = (var10002 + (var10001 != null ? var10001.hashCode() : 0)) * 54189869;
var10001 = this.FIELD_1;
return (var10002 + (var10001 != null ? var10001.hashCode() : 0)) * 54189869 + (this.FIELD_2 ^ 1);
}
public boolean equals(Object var1) {
if (var1 instanceof BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a) {
String var10000 = this.FIELD_0;
String var10001 = ((BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a)var1).FIELD_0;
if (var10001 == null) {
if (var10000 != null) {
return false;
}
} else if (var10000 == null || !var10000.equals(var10001)) {
return false;
}
var10000 = this.FIELD_1;
var10001 = ((BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a)var1).FIELD_1;
if (var10001 == null) {
if (var10000 != null) {
return false;
}
} else if (var10000 == null || !var10000.equals(var10001)) {
return false;
}
if (this.FIELD_2 == ((BeanCopier$BeanCopierKey$$KeyFactoryByCGLIB$$7db7c9a)var1).FIELD_2) {
return true;
}
}
return false;
}
public String toString() {
StringBuffer var10000 = new StringBuffer();
String var10001 = this.FIELD_0;
var10000 = (var10001 != null ? var10000.append(var10001.toString()) : var10000.append("null")).append(", ");
var10001 = this.FIELD_1;
return (var10001 != null ? var10000.append(var10001.toString()) : var10000.append("null")).append(", ").append(this.FIELD_2).toString();
}
}
//代理目标类
package org.springframework.cglib.empty;
public class Object$$BeanCopierByCGLIB$$990b96d1 extends BeanCopier {
public Object$$BeanCopierByCGLIB$$990b96d1() {
}
//看到了吧,其实接近于硬编码
public void copy(Object var1, Object var2, Converter var3) {
CainiaoDTO var10000 = (CainiaoDTO)var2;
CaiNiao var10001 = (CaiNiao)var1;
var10000.setErrorCode(((CaiNiao)var1).getErrorCode());
var10000.setErrorMsg(var10001.getErrorMsg());
var10000.setSuccess(var10001.getSuccess());
}
}

JDK动态代理通过启动项中添加:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//接口
interface Hello {
String sayHello(String str);
}
@Test
public void jdkProxyRun() {
/** 输出jdk动态代理产生的类
* 启动项中添加:-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
* 不能使用System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");原因在于:rt.jar使用AccessController.doPrivileged不能读取项目配置的问题
*/
Hello hello = (Hello) Proxy.newProxyInstance(getClass().getClassLoader(), new Class<?>[]{Hello.class}, new AbstractInvocationHandler() {
private Hello hello;
@Override
protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(hello, args);
}
});
}
/**
* 生成后Hello的jdk动态代理
*/
final class $Proxy4 extends Proxy implements Hello {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy4(InvocationHandler var1) throws  {
super(var1);
}
public final boolean equals(Object var1) throws  {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String sayHello(String var1) throws  {
try {
return (String)super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws  {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws  {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.kxtx.ebill.test.BeanCopy_test$Hello").getMethod("sayHello", Class.forName("java.lang.String"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}

JDK动态代理源码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//源于:sun.misc
public class ProxyGenerator {
//从环境变量中获取配置
private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
//最终调用生成代理class文件
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {//是否生成文件
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");//路径在当前项目下的相对路径
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
return var4;
}
}

BeanCopier源码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public abstract class BeanCopier {
//缓存key
private static final BeanCopier.BeanCopierKey KEY_FACTORY = (BeanCopier.BeanCopierKey)KeyFactory.create(BeanCopier.BeanCopierKey.class);
//copy方法
private static final Signature COPY;
private static final Signature CONVERT;
static {
COPY = new Signature("copy", Type.VOID_TYPE, new Type[]{Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER});
CONVERT = TypeUtils.parseSignature("Object convert(Object, Class, Object)");
}
public static BeanCopier create(Class source, Class target, boolean useConverter) {
BeanCopier.Generator gen = new BeanCopier.Generator();
gen.setSource(source);
gen.setTarget(target);
gen.setUseConverter(useConverter);
return gen.create();
}
//代理类来实现
public abstract void copy(Object var1, Object var2, Converter var3);
public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(BeanCopier.class.getName());
private Class source;
private Class target;
private boolean useConverter;
public Generator() {
super(SOURCE);
}
public BeanCopier create() {
Object key = BeanCopier.KEY_FACTORY.newInstance(this.source.getName(), this.target.getName(), this.useConverter);
return (BeanCopier)super.create(key);
}
//生成BeanCopier的实现类
public void generateClass(ClassVisitor v) {
Type sourceType = Type.getType(this.source);
Type targetType = Type.getType(this.target);
ClassEmitter ce = new ClassEmitter(v);
ce.begin_class(46, 1, this.getClassName(), BeanCopier.BEAN_COPIER, (Type[])null, "<generated>");
EmitUtils.null_constructor(ce);
//BeanCopier.COPY方法,很熟悉吧
CodeEmitter e = ce.begin_method(1, BeanCopier.COPY, (Type[])null);
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(this.source);
PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(this.target);
Map names = new HashMap();
for(int i = 0; i < getters.length; ++i) {
names.put(getters[i].getName(), getters[i]);
}
Local targetLocal = e.make_local();
Local sourceLocal = e.make_local();
if (this.useConverter) {
e.load_arg(1);
e.checkcast(targetType);
e.store_local(targetLocal);
e.load_arg(0);
e.checkcast(sourceType);
e.store_local(sourceLocal);
} else {
e.load_arg(1);
e.checkcast(targetType);
e.load_arg(0);
e.checkcast(sourceType);
}
//生成硬编码get/set的操作
for(int i = 0; i < setters.length; ++i) {
PropertyDescriptor setter = setters[i];
PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName());
if (getter != null) {
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
if (this.useConverter) {
Type setterType = write.getSignature().getArgumentTypes()[0];
e.load_local(targetLocal);
e.load_arg(2);
e.load_local(sourceLocal);
e.invoke(read);
e.box(read.getSignature().getReturnType());
EmitUtils.load_class(e, setterType);
e.push(write.getSignature().getName());
e.invoke_interface(BeanCopier.CONVERTER, BeanCopier.CONVERT);
e.unbox_or_zero(setterType);
e.invoke(write);
} else if (compatible(getter, setter)) {
e.dup2();
e.invoke(read);
e.invoke(write);
}
}
}
e.return_value();
e.end_method();
ce.end_class();
}
}

BeanCopierKey

7db7c9a(有继承层级结构和对象的hascode)。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/197040.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年9月5日 下,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Java动态代理
Java动态代理是一种在运行时对目标类进行拓展的技术。目前,Java动态代理有两种实现方式:JDK和CGLIB(Code Generation Library),下面分别从两个章节对它们进行介绍。
程序猿杜小头
2022/12/01
9400
Java动态代理
CGLIB动态代理原理分析
前一篇文章介绍了CGLIB中常用的API,实际上使用了Enhancer和MethodInterceptor之后会生成代理子类,这篇文章就是分析一下CGLIB动态代理的原理。
Throwable
2020/06/23
5800
深入浅出动态代理
代理模式是为了提供额外或者不同的操作,而插入代替”实际对象”的对象,即代理类,针对代理类的调用操作,都会涉及到与”实际对象”的通信,代理类起到中间人的作用。Java动态代理比代理的思想更进一步,它可以动态的创建代理类并处理对”实际对象”的调用,Java动态代理底层基于Proxy/InvocationHandler相关类和反射技术。
luoxn28
2019/11/06
5030
面试造火箭系列,栽在了cglib和jdk动态代理
“喂,你好,我是XX巴巴公司的技术面试官,请问你是张小帅吗”。声音是从电话那头传来的
程序员老猫
2022/01/04
2450
面试官:策略模式和代理模式有什么区别?
大家好,我是田哥,昨天一哥们面试被问到代理模式,刚好,我也正在写《MyBatis源码分析:小白系列》专栏中的代理模式。
田维常
2022/06/13
3930
面试官:策略模式和代理模式有什么区别?
cglib动态代理实现原理_jdk cglib 动态代理 区别
我们都知道jdk的动态代理内部调用切面无效的问题,而cglib则不会出现这种情况,这是为什么?cglib就一定不会出现内部调用切面无效的问题吗?cglib针对每一个类只创建了一个代理类吗?为什么cglib的效率要比jdk的动态代理低呢?
全栈程序员站长
2022/11/01
1K0
beanCopier_cerdip封装
一、spring的beanutils、hutool的beanutil、cglib的beancopier比较
全栈程序员站长
2022/10/04
5080
终于有人把 Java代理讲清楚了,万字详解!
代理其实不仅仅是在软件开发领域,在我们的日常生活中也是时常可见。比如某p2p老板突然携款带着小姨子跑路了,可怜了下面一堆的程序员背负一身房贷,上有老下有小,程序员只能被迫去申请劳动仲裁,劳动局就会为其指派一位代理律师全权负责程序员的仲裁事宜(PS:p2p跑路仲裁拿回工资的可能性非常低,没让你把工资退回就算好的了)。那这里面就是使用了代理模式,因为在劳动仲裁这个活动中,代理律师会全权代理程序员。比如:房东要将房子出售,于是到房地产中介公司找一个中介(代理),由他来帮房东完成销售房屋,签订合同、网签、贷款过户等等事宜。
程序员小猿
2021/01/19
3030
终于有人把 Java代理讲清楚了,万字详解!
JDK动态代理详解
JDK动态代理是代理模式的一种,且只能代理接口。spring也有动态代理,成为CGLib,现在主要来看一下JDK动态代理是如何实现的?
Liusy
2020/09/01
1.1K0
JDK动态代理详解
JDK动态代理源码学习
继上一篇博客设计模式之代理模式学习之后http://blog.csdn.net/u014427391/article/details/75115928,本博客介绍JDK动态代理的实现原理,学习一下JDK动态代理的源码。 Proxy类。该类即为动态代理类,可以使用反编译工具查看jdk里源码。JDK动态代理实现主要由Proxy类的newProxyInstance()方法实现。实现起来很容易,但是学习都要学习原理,所以本博客主要介绍jdk动态代理实现的源码。
SmileNicky
2019/01/17
4020
java的动态代理底层解析
  代理模式的解释:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展。
忧愁的chafry
2022/10/30
1.4K0
JDK中注解的底层实现
用Java快三年了,注解算是一个常用的类型,特别是在一些框架里面会大量使用注解做组件标识、配置或者策略。但是一直没有深入去探究JDK中的注解到底是什么,底层是怎么实现了?于是参考了一些资料,做了一次稍微详细的分析。
Throwable
2020/06/23
6730
深入理解JDK动态代理机制
基于JDK8 Java中代理的实现一般分为三种 JDK静态代理 JDK动态代理 CGLIB动态代理 在Spring的AOP实现中,主要应用了JDK动态代理以及CGLIB动态代理。本文讨论关于JDK动态代理机制。 代理一般实现的模式为JDK静态代理:创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。 其实就是代理类为被代类预处理消息、过滤消息并在此之后将消息转发给被代类,之
JavaEdge
2018/05/16
6930
抽丝剥茧——代理设计模
代理设计模式在生活中应该很常见了,现在各种中间商的货物代售方便了我们的生活也增加了我们生活的成本。这种生活中的中间商行为就是一种代理模式。
石的三次方
2021/01/05
2700
​面试必备java代理 万字详解!
​代理其实不仅仅是在软件开发领域,在我们的日常生活中也是时常可见。比如某p2p老板突然携款带着小姨子跑路了,可怜了下面一堆的程序员背负一身房贷,上有老下有小,程序员只能被迫去申请劳动仲裁,劳动局就会为其指派一位代理律师全权负责程序员的仲裁事宜(PS:p2p跑路仲裁拿回工资的可能性非常低,没让你把工资退回就算好的了)。那这里面就是使用了代理模式,因为在劳动仲裁这个活动中,代理律师会全权代理程序员。比如:房东要将房子出售,于是到房地产中介公司找一个中介(代理),由他来帮房东完成销售房屋,签订合同、网签、贷款过户等等事宜。
java金融
2020/05/29
4280
​面试必备java代理 万字详解!
23天读懂23种设计模式:代理模式(结构型)
结构型模式讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象实现新的功能(对象结构型模式)。
后台技术汇
2022/05/28
2230
23天读懂23种设计模式:代理模式(结构型)
事物在Controller层的探索
Transaction在Controller层的探索 一般开发中事务要求我们放在Service层,可是有些情况,我们可能会要求放在Controller层,你有没有碰到过这样的需求呢?那么放到Controller层事务会生效吗?会产生什么问题呢?下面一起来看看 I、透过现象看本质 第一种情况 Controller层代码如下 @RestController @RequestMapping("/city") public class CityControllerImpl implements CityCon
Tanyboye
2018/07/02
8810
【小家Java】JDK动态代理技术,你真学会了吗?(Proxy、ProxyClassFactory)
动态代理技术,相信我们都并不陌生。特别是在Spring框架内,大量的使用到了反射以及动态代理技术。但是如果我们只是停留在平时的运用阶段,此篇文章你其实是可以跳过的,因为反射、代理技术一般都只有在框架设计中才会使用到,业务开发是不用接触的。
YourBatman
2019/09/03
4380
【小家Java】JDK动态代理技术,你真学会了吗?(Proxy、ProxyClassFactory)
五、代理模式详解
都知道 SpringAOP 是用代理模式实现,到底是怎么实现的?我们来一探究竟,并且自己仿真手写 还原部分细节。
编程之心
2020/08/12
6380
五、代理模式详解
【深入浅出Java原理及实战】「源码分析系列」深入分析JDK动态代理的分析原理机制
最后发现会对生成的代理类进行缓存,有了,就不直接返回,没有的,还得生成代理类,我们继续往下走:
码界西柚
2023/02/27
2950
【深入浅出Java原理及实战】「源码分析系列」深入分析JDK动态代理的分析原理机制
相关推荐
Java动态代理
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验