前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >obligatory category_cglib为什么比jdk快

obligatory category_cglib为什么比jdk快

作者头像
全栈程序员站长
发布2022-10-29 10:25:13
9980
发布2022-10-29 10:25:13
举报

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

在一些系统代码中,随处可见的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
复制
@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
复制
//接口
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
复制
//源于: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
复制
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

KeyFactoryByCGLIB

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

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

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

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JDK动态代理与CGLIB代理
  • 生成后代理类究竟怎样的你知道么
  • JDK动态代理源码
  • BeanCopier源码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档