文章目录
JDK 动态代理
Java API
InvocationHandler
java.lang.reflect.InvocationHandler,代理方法处理接口。每个代理实例对象都要关联一个 InvocationHandler,当调用方法执行到代理时,由重写的 InvocationHandler.invoke 方法作为实际的代理执行者。
public interface InvocationHandler {
/**
* @param proxy 代理实例对象($ProxyX extends Proxy implements some interface)
* @param method 代理实例对象要调用的源目标方法(即拦截的方法,此处应指向代理的接口方法和Object的方法)
* @param args 调用源目标方法时的入参
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
Proxy
java.lang.reflect.Proxy,提供静态方法用于创建代理类和代理实例对象,并且是所有 JDK 动态代理类的父类。
public class Proxy implements java.io.Serializable {
// 代理类的缓存
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
// 代理实例对象的调用处理器(实际处理代理方法的执行者)
protected InvocationHandler h;
private Proxy() {}
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
/**
* 创建代理类
*
* @param loader 类加载器,一般传被代理类的类加载器
* @param interfaces 代理的接口Class数组
*/
@CallerSensitive
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException
{
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 先从缓存找,没有创建代理类
return getProxyClass0(loader, intfs);
}
/**
* 创建代理实例对象
*
* @param loader 类加载器,一般传被代理类的类加载器
* @param interfaces 代理的接口Class数组
* @param h 代理方法处理器
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// ...
Class<?> cl = getProxyClass0(loader, intfs);
// ...
// 使用构造方法(带InvocationHandler的构造方法),创建并返回代理实例对象
return cons.newInstance(new Object[]{h});
}
}
原理
Proxy 创建一个继承 Proxy 并实现指定接口的类 $ProxyX ,通过重写 InvocationHandler 的 invoke 方法,由 invoke 方法去代理指定接口的方法。
// Proxy内部静态类,根据提供的ClassLoader和Class<?>[] interfaces,创建并返回代理类
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// ...
// 代理类类名中X的系号值
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
// ...
// 创建代理类(自验证可以参照这个,将字节数组{即字节码的二进制数据}输出到文件{.class}中去,然后利用IDEA反编译看结果,如下面的$Proxy2示例)
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
// native加载并返回类对象
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
}
JDK 方式代理类字节码示例
public final class $Proxy2 extends Proxy implements Player {
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m2;
private static Method m0;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
// ...Player接口的方法
m3 = Class.forName("org.jk.business.model.proxy.Player").getMethod("playShow");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
// 入参为InvocationHandler的构造方法,super调用Proxy中h的赋值
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
// ... 相关代理方法
// 举例:toString、hashCode、equals等Object的方法也会被代理
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);
}
}
// ...
}
为什么要继承Proxy
通俗答案:
- 代理实例对象需要持有 InvocationHandler ,如果不继承 Proxy 就需要在每个创建的代理类里都加上该属性,不是很好的实现抽象逻辑;
- 判断对象或者类是否是被 JDK 代理过的结果,不好判断,如果继承了 Proxy 就可以通过判断是否为 Proxy 的子类来作为一部分依据。Proxy 提供了 Proxy.isProxyClass(Class<?> cl) 。
使用示例
(1)先获取代理类,再创建代理实例对象 Proxy.getProxyClass
// 声明接口
public interface IPlayer {
String playShow();
String fetchSalary();
}
@Getter
@Setter
public class MoviePlayer implements IPlayer {
private String name;
@Override
public String playShow() {
// do sth
return "good";
}
@Override
public String fetchSalary() {
return "1爽";
}
}
// 被代理对象的持有者,代理逻辑的真正执行者(实例将会被赋值给Proxy的属性 h)
@AllArgsConstructor
class PlayerHolder implements InvocationHandler {
private IPlayer player;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// befor do sth
// 注意:proxy是代理实例对象,不能直接method.invoke(proxy, args),这样会形成递归调用,最终栈溢出;因此使用Holder持有被代理对象的方式来调用源方法
Object result = method.invoke(player, args);
// after do sth
return result;
}
}
// 使用
@Test
public void testJDKProxyWhenGetProxyClass() {
MoviePlayer moviePlayer = new MoviePlayer();
// proxyClass使用构造器去创建实例
Class<?> proxyClass = Proxy.getProxyClass(IPlayer.class.getClassLoader(), IPlayer.class);
// playerProxyInstance:代理实例对象
IPlayer playerProxyInstance = (IPlayer)proxyClass.getConstructor(InvocationHandler.class).newInstance(new PlayerHolder(moviePlayer));
}
(2)Proxy直接创建代理实例对象 Proxy.newProxyInstance
@Test
public void testJDKProxyWhenNewProxyInstance() {
MoviePlayer moviePlayer = new MoviePlayer();
IPlayer playerProxyInstance = (IPlayer)Proxy.newProxyInstance(IPlayer.class.getClassLoader(), new Class[]{IPlayer.class}, new PlayerHolder(moviePlayer));
}
CGLib 动态代理
通过动态地生成一个子类去覆盖所要代理的类(非 final 修饰的类和方法)。CGLib 底层使用了 ASM 来操作字节码生成新的类,ASM 使用类似 SAX 的解析器来实现高性能。
Java API
MethodInterceptor
org.springframework.cglib.proxy.MethodInterceptor ,代理方法处理接口,继承 Callback 接口。
package org.springframework.cglib.proxy; public interface Callback { } public interface MethodInterceptor extends Callback { /** * @param o 代理实例对象 * @param method 被代理方法 * @param objects 被代理方法入参 * @param methodProxy 被代理方法对应的MethodProxy对象 */ Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable; }
Enhancer
创建子类去实现方法的拦截。
public interface CallbackFilter { // method:被代理的方法;返回 Callback 数组对应的回调处理器的下标,即指定该方法用哪个 Callback回调处理(注意:这是创建代理类生成字节码时使用) int accept(Method method); boolean equals(Object var1); } public class Enhancer extends AbstractClassGenerator { // 被代理类 private Class superclass; // 被代理接口 private Class[] interfaces; // 回调过滤 private CallbackFilter filter; // 回调函数 private Callback[] callbacks; // 设置被代理的类(如果 superclass 是接口,则内部会调用 setInterfaces) public void setSuperclass(Class superclass) { // 。。。 } public void setInterfaces(Class[] interfaces) { this.interfaces = interfaces; } // 设置被代理的方法的回调过滤处理 public void setCallbackFilter(CallbackFilter filter) { this.filter = filter; } // 设置回调处理(即方法的拦截,真正的业务代理逻辑) public void setCallbacks(Callback[] callbacks) { if (callbacks != null && callbacks.length == 0) { throw new IllegalArgumentException("Array cannot be empty"); } this.callbacks = callbacks; } // 创建代理类(ignore any callbacks that have been set) public Class createClass() { classOnly = true; return (Class) createHelper(); } // 创建代理对象实例 public Object create() { classOnly = false; argumentTypes = null; return createHelper(); } // 用指定的构造方法创建代理对象实例 public Object create(Class[] argumentTypes, Object[] arguments) { classOnly = false; if (argumentTypes == null || arguments == null || argumentTypes.length != arguments.length) { throw new IllegalArgumentException("Arguments must be non-null and of equal length"); } this.argumentTypes = argumentTypes; this.arguments = arguments; return createHelper(); } private Object createHelper() { preValidate(); // 根据类/接口、callback等信息,创建一个key,用key去判断代理类是否已缓存 Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null, ReflectUtils.getNames(interfaces), filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter), callbackTypes, useFactory, interceptDuringConstruction, serialVersionUID); this.currentKey = key; // AbstractClassGenerator.create Object result = super.create(key); return result; } /* * DefaultGeneratorStrategy.generate调用Enhancer.generateClass来完成真正的创建工作 * 拼装字节码数据(关键步骤) */ public void generateClass(ClassVisitor v) throws Exception { // ... } }
AbstractClassGenerator
所有代码生成 CGLIB 实用程序的抽象类,包含代理类、代理对象的创建以及代理类的缓存等。
abstract public class AbstractClassGenerator<T> implements ClassGenerator {
// 类加载器-代理类的缓存(静态变量)
// 代理类生成策略
// 代理类类名称生成策略
// 影响代理类生成的一些变量
// 。。。
protected Object create(Object key) {
// ...
ClassLoaderData data = cache.get(loader);
// ...
Object obj = data.get(this, getUseCache());
if (obj instanceof Class) {
return firstInstance((Class) obj);
}
return nextInstance(obj);
}
//内部类ClassLoaderData
protected static class ClassLoaderData {
public ClassLoaderData(ClassLoader classLoader) {
// 赋值属性generatedClasses的值(省略,细节看源码)
public Object apply(AbstractClassGenerator gen) {
Class klass = gen.generate(ClassLoaderData.this);
// 最终调用子类Enhancer.wrapCachedClass(klass)
return gen.wrapCachedClass(klass);
}
// 上面的data.get触发gen.generate
}
}
// 执行代理类创建
protected Class generate(ClassLoaderData data) {
// ...
// strategy可以自定义,当前默认 DefaultGeneratorStrategy.INSTANCE
byte[] b = strategy.generate(this);
String className = ClassNameReader.getClassName(new ClassReader(b));
ProtectionDomain protectionDomain = getProtectionDomain();
synchronized (classLoader) { // just in case
// SPRING PATCH BEGIN
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain, contextClass);
// SPRING PATCH END
}
return gen;
}
}
Factory
Enhancer 根据属性 useFactory 决定创建的代理类是否实现 Factory 接口,Factory 接口提供根据已创建的代理类来生成额外的代理实例对象。
public interface Factory { // 传入新的Callback,变更原代理类的回调函数 Object newInstance(Callback var1); Object newInstance(Callback[] var1); Object newInstance(Class[] var1, Object[] var2, Callback[] var3); Callback getCallback(int var1); void setCallback(int var1, Callback var2); void setCallbacks(Callback[] var1); Callback[] getCallbacks(); }
原理
Enhancer 通过创建被代理类的子类,并设置Callback(MethodInterceptor)对目标方法进行增强,实现对目标对象的代理。
在代理类中,一个目标方法对应两个方法,如目标中方法为
playShow()
,则代理类中会存在CGLIB$playShow$X()
和playShow()
。其中,CGLIB$playShow$X()
方法 X 是序数,表示目标方法在所有被代理的目标方法中的排序,内部直接调用super.playShow()
即直接调用目标类的方法,不进行增强;playShow()
则是调用对应的MethodInterceptor.intercept(...)
完成代理增强任务。与 JDK 动态代理一样,toString 等方法也会被代理。
CGLib 方式代理类字节码示例
public class MoviePlayer$$EnhancerByCGLIB$$d021d817 extends MoviePlayer implements Factory {
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
// 回调方法数组,代理类构建时Enhancer的参数值
private static final Callback[] CGLIB$STATIC_CALLBACKS;
// 回调方法进行目标方法拦截,代理增强,每个Callback对应一个MethodInterceptor属性
private MethodInterceptor CGLIB$CALLBACK_0;
private MethodInterceptor CGLIB$CALLBACK_1;
private MethodInterceptor CGLIB$CALLBACK_2;
// 。。。
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$fetchSalary$1$Method;
private static final MethodProxy CGLIB$fetchSalary$1$Proxy;
// CGLIB$playShow$2$Method:目标方法playShow的源Method对象
private static final Method CGLIB$playShow$2$Method;
// CGLIB$playShow$2$Proxy:目标方法playShow的MethodProxy对象
private static final MethodProxy CGLIB$playShow$2$Proxy;
// 。。。
static {
CGLIB$STATICHOOK1();
}
static void CGLIB$STATICHOOK1() {
// CGLIB$THREAD_CALLBACKS:useFactory时,可以用Factory的方法设置Callback,这里的ThreadLocal就用来在创建新代理对象实例的时候,newInstance(...)防止其他线程的干扰。
CGLIB$THREAD_CALLBACKS = new ThreadLocal();
CGLIB$emptyArgs = new Object[0];
// var0:代理类Class对象;var1:目标类Class对象
Class var0 = Class.forName("org.jk.business.model.proxy.MoviePlayer$$EnhancerByCGLIB$$d021d817");
Class var1;
Method[] var10000 = ReflectUtils.findMethods(new String[]{"setName", "(Ljava/lang/String;)V", "fetchSalary", "()Ljava/lang/String;", "playShow", "()Ljava/lang/String;"}, (var1 = Class.forName("org.jk.business.model.proxy.MoviePlayer")).getDeclaredMethods());
// 。。。
CGLIB$playShow$2$Method = var10000[2];
CGLIB$playShow$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "playShow", "CGLIB$playShow$2");
// 。。。
}
// 代理类的构造方法
public MoviePlayer$$EnhancerByCGLIB$$d021d817() {
CGLIB$BIND_CALLBACKS(this);
}
public MoviePlayer$$EnhancerByCGLIB$$d021d817(String var1) {
super(var1);
CGLIB$BIND_CALLBACKS(this);
}
// 为callback绑定methodinterceptor值
private static final void CGLIB$BIND_CALLBACKS(Object var0) {
MoviePlayer$$EnhancerByCGLIB$$d021d817 var1 = (MoviePlayer$$EnhancerByCGLIB$$d021d817)var0;
if (!var1.CGLIB$BOUND) {
var1.CGLIB$BOUND = true;
// 判断threadlocal中有没有,没有取代理类创建的默认值(即Enhancer构建时的参数)
Object var10000 = CGLIB$THREAD_CALLBACKS.get();
if (var10000 == null) {
var10000 = CGLIB$STATIC_CALLBACKS;
if (var10000 == null) {
return;
}
}
Callback[] var10001 = (Callback[])var10000;
var1.CGLIB$CALLBACK_3 = (MethodInterceptor)((Callback[])var10000)[3];
var1.CGLIB$CALLBACK_2 = (MethodInterceptor)var10001[2];
var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];
var1.CGLIB$CALLBACK_0 = (MethodInterceptor)var10001[0];
}
}
// 。。。
/**
* 目标方法对应代理类中的2个方法:CGLIB$playShow$2、playShow
* CGLIB$playShow$2 直接调用父类的方法,相当于没有进行增强;
* playShow 使用MethodInterceptor进行了增强
*/
final String CGLIB$playShow$2() {
return super.playShow();
}
public final String playShow() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$playShow$2$Method, CGLIB$emptyArgs, CGLIB$playShow$2$Proxy) : super.playShow();
}
// 。。。
}
MethodProxy
当拦截到被代理方法时,代理类方法将 MethodProxy 对象作为入参传递给 MethodInterceptor.intercept(),MethodProxy.invoke 和 MethodProxy.invokeSuper 负责调用目标方法,MethodProxy中则通过 FastClass 的机制进行方法调用的优化。
通过 FastClass 代理类加方法索引下标的方式,实现了从反射调用到直接调用的转变。
启动VM参数配置
-Dcglib.debugLocation=F:\
即可将字节码文件输出到指定目录下。public class MethodProxy { private Signature sig1; private Signature sig2; private CreateInfo createInfo; private final Object initLock = new Object(); // 通过 FastClassInfo 优化目标方法的执行 private volatile FastClassInfo fastClassInfo; // 。。。 private static class FastClassInfo { // 目标类的 FastClass 代理类对象 FastClass f1; // 代理类的 FastClass 代理类对象 FastClass f2; // 目标方法对应的第一个代理方法(如上面的CGLIB$playShow$2)在 f1 中的方法索引下标 int i1; // 目标方法对应的第二个代理方法(如上面的playShow)在 f2 中的方法索引下标 int i2; } private void init() { if (fastClassInfo == null) { synchronized (initLock) { if (fastClassInfo == null) { CreateInfo ci = createInfo; // 创建FastClassInfo和对应的FastClass信息(helper里也是动态代理,因此对于同一个目标类会有FastClass的缓存) FastClassInfo fci = new FastClassInfo(); fci.f1 = helper(ci, ci.c1); fci.f2 = helper(ci, ci.c2); // 获取对应方法签名的方法索引下标 fci.i1 = fci.f1.getIndex(sig1); fci.i2 = fci.f2.getIndex(sig2); fastClassInfo = fci; createInfo = null; } } } } // 将会调用代理类中的 CGLIB$xxx$x()方法 public Object invokeSuper(Object obj, Object[] args) throws Throwable { try { init(); FastClassInfo fci = fastClassInfo; // 调用 FastClass 代理类对象的 invoke 方法,传入方法索引下标、目标代理类实例对象、方法参数 return fci.f2.invoke(fci.i2, obj, args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } }
FastClass 代理类字节码示例
本示例是代理类的 FastClass 代理类对象的示例
public class MoviePlayer$$EnhancerByCGLIB$$1a11a229$$FastClassByCGLIB$$339c2fad extends FastClass { public MoviePlayer$$EnhancerByCGLIB$$1a11a229$$FastClassByCGLIB$$339c2fad(Class var1) { super(var1); } public int getIndex(String var1, Class[] var2) { switch(var1.hashCode()) { case -679231402: if (var1.equals("playShow")) { switch(var2.length) { case 0: return 8; } } break; case -137950106: if (var1.equals("CGLIB$playShow$2")) { switch(var2.length) { case 0: return 20; } } break; } // ... } public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException { // var2是MethodProxy中 invokeSuper 传入的值,强转为代理类 MoviePlayer$$EnhancerByCGLIB$$d021d817 var10000 = (MoviePlayer$$EnhancerByCGLIB$$d021d817)var2; int var10001 = var1; try { switch(var10001) { // ... case 8: return var10000.playShow(); // ... // 根据对应下标,调用对应的目标代理类的方法,不再是反射调用的方式 case 20: return var10000.CGLIB$playShow$2(); // ... } } } }
使用示例
// 声明接口
public interface IPlayer {
String playShow();
String fetchSalary();
}
// 目标类
@Getter
@Setter
public class MoviePlayer implements IPlayer {
private String name;
@Override
public String playShow() {
// do sth
return "good";
}
@Override
public String fetchSalary() {
return "1爽";
}
}
// 代理类创建工具
public class PlayerCglibProxy {
// 根据目标对象创建代理对象
public Object getIPlayerInstance(IPlayer player) throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(player.getClass());
// 设置4个方法拦截(前面3个是为了体现 callbackFilter 的作用)
enhancer.setCallbacks(new Callback[]{createCallback("callback1"), createCallback("callback2"), createCallback("callback3"),
new PlayerHolder(player)});
// 设置拦截过滤,对于指定方法选择指定的callback处理
enhancer.setCallbackFilter(new CallbackFilter() {
Random random = new Random();
@Override
public int accept(Method method) {
// 如果不是playShow,则从Callback[]随机选择一个callback,0-2
if (!method.getName().equals("playShow")) {
return random.nextInt(3);
}
return 3;
}
});
// 创建代理实例对象
return enhancer.create();
}
private MethodInterceptor createCallback(String displayName) {
return new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println(displayName);
return method.invoke(target, objects);
}
};
}
@AllArgsConstructor
class PlayerHolder implements MethodInterceptor {
private IPlayer player;
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// befor do sth
Object result = methodProxy.invokeSuper(o, objects);
// 或者(这样就走的反射):Object result = method.invoke(player, objects);
// after do sth
return result;
}
}
}
@Test
public void testJDKProxyWhenNewProxyInstance() {
MoviePlayer moviePlayer = new MoviePlayer();
PlayerCglibProxy proxy = new PlayerCglibProxy();
IPlayer playerProxyInstance = (IPlayer)proxy.getIPlayerInstance(moviePlayer);
}
两种动态代理方式对比
(1)继承关系:JDK 方式需要目标类提供接口,生成的代理类继承 Proxy 并实现指定的接口;CGLib 方式不需要目标类一定提供接口,生成的代理类继承目标类(也可以只提供接口,不提供目标类);因此 CGLib 可以为没有实现接口的目标类进行代理增强,更加灵活一些。
(2)调用方式:JDK 方式使用反射的机制去调用目标方法,CGLib 使用 FastClass 代理类对象直接调用目标方法,理论上效率更高(但目前高版本的 JDK 测试中,JDK 方式效率甚至比 CGLib 高,这点还需要继续验证。)
参考文档