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

在一些系统代码中,随处可见的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() {

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, "");

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

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

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

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