cglib 如何避免反射
点击查看模拟代码
/**
* 模拟 methodProxy invoke() 方法调用生成的代理类,和代理对象配合使用
* 为什么类名是 FastClass 呢,因为动态生成的代理类的父接口就是它
*/
public class S13ProxyFastClass {
private Signature ss1 = new Signature("ss120", "()V");
private Signature ss2 = new Signature("ss121", "(I)V");
private Signature ss3 = new Signature("ss122", "(II)V");
// 获取代理方法的编号,编号可以随意,只要能区分即可
/*
Target
save() 0
save(int) 1
save(int,int) 2
signature 包括方法名字、参数返回值 不存在返回 -1
*/
public int getIndex(Signature signature) {
if (ss1.equals(signature)) {
return 1;
} else if (ss2.equals(signature)) {
return 3;
} else if (ss3.equals(signature)) {
return 5;
}
return -1;
}
/**
* 根据方法编号,调用目标对象的方法
*/
public Object invoke(int index, Object proxy, Object[] args) {
if (index == 1) {
((S12Proxy) proxy).ss120();
return null; // 无返回值返回 null
} else if (index == 3) {
((S12Proxy) proxy).ss121((int) args[0]);
return null;
} else if (index == 5) {
((S12Proxy) proxy).ss122((int) args[0], (int) args[1]);
return null;
} else {
throw new RuntimeException("无此方法");
}
}
}
/**
* methodProxy invoke() 方法调用时生成的代理类,配合目标对象使用
*/
public class S13TargetFastClass {
private Signature s1 = new Signature("s120", "()V");
private Signature s2 = new Signature("s121", "(I)V");
private Signature s3 = new Signature("s122", "(II)V");
// 获取目标方法的编号,编号可以随意,只要能区分即可
/*
Target
save() 0
save(int) 1
save(long) 2
signature 包括方法名字、参数返回值 不存在返回 -1
*/
public int getIndex(Signature signature) {
if (s1.equals(signature)) {
return 0;
} else if (s2.equals(signature)) {
return 1;
} else if (s3.equals(signature)) {
return 2;
}
return -1;
}
/**
* 根据方法编号,调用目标对象的方法
*/
public Object invoke(int index, Object target, Object[] args) {
if (index == 0) {
((S12Target) target).s120();
return null; // 无返回值返回 null
} else if (index == 1) {
((S12Target) target).s121((int) args[0]);
return null;
} else if (index == 2) {
((S12Target) target).s122((int) args[0], (int) args[1]);
return null;
} else {
throw new RuntimeException("无此方法");
}
}
}
//测试
public static void main(String[] args) {
testTargetFastClass(new Signature("s120", "()V"));
testProxyFastClass(new Signature("ss120", "()V"), new Object[]{});
testProxyFastClass(new Signature("ss122", "(II)V"), new Object[]{1,3});
}
private static void testTargetFastClass(Signature s) {
S13TargetFastClass fastClass = new S13TargetFastClass();
int index = fastClass.getIndex(s);
fastClass.invoke(index, new S12Target(), new Object[]{});
}
private static void testProxyFastClass(Signature s, Object[] args) {
S13ProxyFastClass fastClass = new S13ProxyFastClass();
int index = fastClass.getIndex(s);
fastClass.invoke(index, new S12Proxy(), args);
}
点击查看 methodProxy 源代码
package org.springframework.cglib.proxy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.springframework.cglib.core.AbstractClassGenerator;
import org.springframework.cglib.core.CodeGenerationException;
import org.springframework.cglib.core.GeneratorStrategy;
import org.springframework.cglib.core.NamingPolicy;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastClass.Generator;
public class MethodProxy {
private Signature sig1;
private Signature sig2;
private MethodProxy.CreateInfo createInfo;
private final Object initLock = new Object();
private volatile MethodProxy.FastClassInfo fastClassInfo;
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
proxy.sig1 = new Signature(name1, desc);
proxy.sig2 = new Signature(name2, desc);
proxy.createInfo = new MethodProxy.CreateInfo(c1, c2);
return proxy;
}
private void init() {
if (this.fastClassInfo == null) {
synchronized(this.initLock) {
if (this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
private static FastClass helper(MethodProxy.CreateInfo ci, Class type) {
Generator g = new Generator();
g.setType(type);
g.setContextClass(type);
g.setClassLoader(ci.c2.getClassLoader());
g.setNamingPolicy(ci.namingPolicy);
g.setStrategy(ci.strategy);
g.setAttemptLoad(ci.attemptLoad);
return g.create();
}
private MethodProxy() {
}
public Signature getSignature() {
return this.sig1;
}
public String getSuperName() {
return this.sig2.getName();
}
public int getSuperIndex() {
this.init();
return this.fastClassInfo.i2;
}
FastClass getFastClass() {
this.init();
return this.fastClassInfo.f1;
}
FastClass getSuperFastClass() {
this.init();
return this.fastClassInfo.f2;
}
public static MethodProxy find(Class type, Signature sig) {
try {
Method m = type.getDeclaredMethod("CGLIB$findMethodProxy", MethodInterceptorGenerator.FIND_PROXY_TYPES);
return (MethodProxy)m.invoke((Object)null, sig);
} catch (NoSuchMethodException var3) {
throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor");
} catch (InvocationTargetException | IllegalAccessException var4) {
throw new CodeGenerationException(var4);
}
}
public Object invoke(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
return fci.f1.invoke(fci.i1, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
} catch (IllegalArgumentException var5) {
if (this.fastClassInfo.i1 < 0) {
throw new IllegalArgumentException("Protected method: " + this.sig1);
} else {
throw var5;
}
}
}
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
private static class CreateInfo {
Class c1;
Class c2;
NamingPolicy namingPolicy;
GeneratorStrategy strategy;
boolean attemptLoad;
public CreateInfo(Class c1, Class c2) {
this.c1 = c1;
this.c2 = c2;
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
if (fromEnhancer != null) {
this.namingPolicy = fromEnhancer.getNamingPolicy();
this.strategy = fromEnhancer.getStrategy();
this.attemptLoad = fromEnhancer.getAttemptLoad();
}
}
}
private static class FastClassInfo {
FastClass f1;
FastClass f2;
int i1;
int i2;
private FastClassInfo() {
}
}
}
- 当调用 MethodProxy 的 invoke 或 invokeSuper 方法时, 会动态生成两个类
- ProxyFastClass 配合代理对象一起使用, 避免反射
- TargetFastClass 配合目标对象一起使用, 避免反射 (Spring 用的这种)
- TargetFastClass 记录了 Target 中方法与编号的对应关系
- save(long) 编号 2
- save(int) 编号 1
- save() 编号 0
- 首先根据方法名和参数个数、类型, 用 switch 和 if 找到这些方法编号
- 然后再根据编号去调用目标方法, 又用了一大堆 switch 和 if, 但避免了反射
- 方法编号多少无所谓,只要每个方法可以区分开就行
- ProxyFastClass 记录了 Proxy 中方法与编号的对应关系,不过 Proxy 额外提供了下面几个方法
- saveSuper(long) 编号 2,不增强,仅是调用 super.save(long)
- saveSuper(int) 编号 1,不增强, 仅是调用 super.save(int)
- saveSuper() 编号 0,不增强, 仅是调用 super.save()
- 查找方式与 TargetFastClass 类似
- 为什么有这么麻烦的一套东西呢?
- 避免反射, 提高性能, 代价是一个代理类配两个 FastClass 类, 代理类中还得增加仅调用 super 的一堆方法
- 用编号处理方法对应关系比较省内存, 另外, 最初获得方法顺序是不确定的, 这个过程没法固定死