大家好,又见面了,我是你们的朋友全栈君。
在一些系统代码中,随处可见的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
7db7c9a(有继承层级结构和对象的hascode)。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/197040.html原文链接:https://javaforall.cn