JDK
Jdk代理的最简单模拟, 由前文可知 JDK动态代理需要实现接口,所以基于此,进行最简单的模拟。
package com.example.proxy; public class Jdk { interface Foo { void foo(); } static class Target implements Foo { @Override public void foo() { System.out.println("foo"); } } // 代理类 static class $Proxy0 implements Foo { @Override public void foo() { // 1. 功能增强 System.out.println("before"); // 2. 调用目标 new Target().foo(); } } public static void main(String[] args) { Foo f = new $Proxy0(); f.foo(); } }
虽然简单实现了代理,但是目前增强是固定的,但是在实际应用中,使用到代理类,方法是不可能固定的,所以接下来进行优化一下。使用抽象类+模版方法设置代理的执行逻辑。
package com.example.proxy; public class Jdk { interface Foo { void foo(); } static abstract class InvokeHandler { abstract Object invoke(); } // 代理类 static class $Proxy0 implements Foo { private final InvokeHandler invokeHandler; $Proxy0(InvokeHandler invokeHandler) { this.invokeHandler = invokeHandler; } @Override public void foo() { // 1. 功能增强 System.out.println("before"); // 2. 调用目标 invokeHandler.invoke(); } } public static void main(String[] args) { Foo f = new $Proxy0(new InvokeHandler() { @Override Object invoke() { System.out.println(">>>>>>>> foo"); return null; } }); f.foo(); } }
至此,方法就是可以不再固定。但是很显然,代理的对象不可能永远只有一个方法,所以想办法动态设置。
package com.example.proxy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Jdk { interface Foo { void foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; void bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; } static abstract class InvokeHandler { abstract Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException; } // 代理类 static class $Proxy0 implements Foo { private final InvokeHandler invokeHandler; $Proxy0(InvokeHandler invokeHandler) { this.invokeHandler = invokeHandler; } @Override public void foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // 1. 功能增强 System.out.println("before"); // 2. 调用目标 invokeHandler.invoke(Foo.class.getMethod("foo"), new Object[0]); } @Override public void bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // 1. 功能增强 System.out.println("before"); // 2. 调用目标 invokeHandler.invoke(Foo.class.getMethod("bar"), new Object[0]); } } static class Target implements Foo { @Override public void foo() { System.out.println("target foo"); } @Override public void bar() { System.out.println("target bar"); } } public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Foo f = new $Proxy0(new InvokeHandler() { @Override Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException { // 传入代理对象 method.invoke(new Target(), params); return null; } }); f.foo(); f.bar(); } }
/**
运行结果
before
target foo
before
target bar
**/
到这里,可以发现,多方法的代理对象也可以正常执行。但是如果执行方法有值返回呢,这个也简单,小修改一波。
package com.example.proxy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Jdk { interface Foo { Object foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; Object bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; } static abstract class InvokeHandler { abstract Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException; } // 代理类 static class $Proxy0 implements Foo { private final InvokeHandler invokeHandler; $Proxy0(InvokeHandler invokeHandler) { this.invokeHandler = invokeHandler; } @Override public Object foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // 1. 功能增强 System.out.println("before"); // 2. 调用目标 return invokeHandler.invoke(Foo.class.getMethod("foo"), new Object[0]); } @Override public Object bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // 1. 功能增强 System.out.println("before"); // 2. 调用目标 return invokeHandler.invoke(Foo.class.getMethod("bar"), new Object[0]); } } static class Target implements Foo { @Override public Integer foo() { System.out.println("target foo"); return 1; } @Override public String bar() { System.out.println("target bar"); return "hello"; } } public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Foo f = new $Proxy0(new InvokeHandler() { @Override Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException { // 传入代理对象 return method.invoke(new Target(), params); } }); System.out.println(f.foo()); System.out.println(f.bar()); } }
/** 运行结果 before target foo 1 before target bar hello **/
在源码实现中,方法还可以被缓存复用,不需要每次都重新创建。
package com.example.proxy; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; public class Jdk { interface Foo { Object foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; Object bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException; } static abstract class InvokeHandler { abstract Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException; } // 代理类 static class $Proxy0 implements Foo { private final InvokeHandler invokeHandler; private final Map<String, Method> cache = new HashMap<>(); $Proxy0(InvokeHandler invokeHandler) { this.invokeHandler = invokeHandler; } @Override public Object foo() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // 1. 功能增强 System.out.println("before"); // 2. 调用目标 Method foo = cache.getOrDefault("foo", null); if(foo == null) { foo = Foo.class.getMethod("foo"); System.out.println(">>>>>> 新创建方法"); cache.put("foo", foo); } return invokeHandler.invoke(foo, new Object[0]); } @Override public Object bar() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // 1. 功能增强 System.out.println("before"); // 2. 调用目标 Method bar = cache.getOrDefault("bar", null); if(bar == null) { bar = Foo.class.getMethod("foo"); System.out.println(">>>>>> 新创建方法"); cache.put("bar", bar); } return invokeHandler.invoke(bar, new Object[0]); } } static class Target implements Foo { @Override public Integer foo() { System.out.println("target foo"); return 1; } @Override public String bar() { System.out.println("target bar"); return "hello"; } } public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Foo f = new $Proxy0(new InvokeHandler() { @Override Object invoke(Method method, Object[] params) throws InvocationTargetException, IllegalAccessException { // 传入代理对象 return method.invoke(new Target(), params); } }); System.out.println(f.foo()); System.out.println(f.bar()); System.out.println(f.foo()); System.out.println(f.bar()); } }
/** before >>>>>> 新创建方法 target foo 1 before >>>>>> 新创建方法 target foo 1 before target foo 1 before target foo 1 **/
到此,代理方法只会被寻找一次。
JDK 动态代理生成的代理类是以字节码的形式存在的,并不存在所谓的 .java 文件,但也不是说就没办法看到生成的代理类信息了。不过可
以使用 arthas反编译,看到字节码。
arthas 反编译jdk代理对象
比如:
package com.example.proxy; import java.io.IOException; import java.lang.reflect.Proxy; public class Jdk1 { interface Foo { void foo(); } static final class Target implements Foo { @Override public void foo() { System.out.println("target foo"); } } public static void main(String[] args) throws IOException { // 原始对象 Target target = new Target(); // 用来加载在运行期间动态生成的字节码 ClassLoader classLoader = Jdk1.class.getClassLoader(); Foo proxy = (Foo) Proxy.newProxyInstance(classLoader, new Class[]{Foo.class}, (p, method, params) -> { System.out.println("before..."); // 目标.方法(参数) --> 方法.invoke(目标, 参数) Object result = method.invoke(target, params); System.out.println("after..."); // 也返回目标方法执行的结果 return result; }); // 打印代理类的全限定类名 System.out.println(proxy.getClass()); proxy.foo(); // 只要不在控制台上输入并回车,程序就不会终端 System.in.read(); } }
打印的结果是:
class com.example.proxy.$Proxy0 before... target foo after...
arthas 反编译的结果是:
[arthas@60054]$ jad com.example.proxy.$Proxy0
ClassLoader:
±jdk.internal.loader.ClassLoadersA p p C l a s s L o a d e r @ 251 a 69 d 7 + − j d k . i n t e r n a l . l o a d e r . C l a s s L o a d e r s AppClassLoader@251a69d7 +-jdk.internal.loader.ClassLoadersAppClassLoader@251a69d7+−jdk.internal.loader.ClassLoadersPlatformClassLoader@17747fbe
Location:
/* * Decompiled with CFR. * * Could not load the following classes: * com.example.proxy.Jdk1$Foo */ package com.example.proxy; import com.example.proxy.Jdk1; import java.lang.invoke.MethodHandles; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; final class $Proxy0 extends Proxy implements Jdk1.Foo { private static final Method m0; private static final Method m1; private static final Method m2; private static final Method m3; private static MethodHandles.Lookup proxyClassLookup(MethodHandles.Lookup lookup) throws IllegalAccessException { if (lookup.lookupClass() == Proxy.class && lookup.hasFullPrivilegeAccess()) { return MethodHandles.lookup(); } throw new IllegalAccessException(lookup.toString()); } public $Proxy0(InvocationHandler invocationHandler) { super(invocationHandler); } static { try { m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("com.example.proxy.Jdk1$Foo").getMethod("foo", new Class[0]); return; } catch (NoSuchMethodException noSuchMethodException) { throw new NoSuchMethodError(noSuchMethodException.getMessage()); } catch (ClassNotFoundException classNotFoundException) { throw new NoClassDefFoundError(classNotFoundException.getMessage()); } } public final void foo() { try { this.h.invoke(this, m3, null); return; } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final boolean equals(Object object) { try { return (Boolean)this.h.invoke(this, m1, new Object[]{object}); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final String toString() { try { return (String)this.h.invoke(this, m2, null); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } public final int hashCode() { try { return (Integer)this.h.invoke(this, m0, null); } catch (Error | RuntimeException throwable) { throw throwable; } catch (Throwable throwable) { throw new UndeclaredThrowableException(throwable); } } }
CGlib
cglib 代理类继承目标对象。
public class Target { public void save() { System.out.println("0"); } public void save(int i) { System.out.println(i); } public void save(long l) { System.out.println(l); } } //- cglib 代理模拟 public class Proxy extends Target{ private MethodInterceptor methodInterceptor; public void setMethodInterceptor(MethodInterceptor methodInterceptor) { this.methodInterceptor = methodInterceptor; } private static final Method save0; private static final Method save1; private static final Method save2; static { try { save0 = Target.class.getMethod("save"); save1 = Target.class.getMethod("save", int.class); save2 = Target.class.getMethod("save", long.class); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } @Override public void save() { try { methodInterceptor.intercept(this, save0, new Object[0], null); } catch (Throwable e) { throw new RuntimeException(e); } } @Override public void save(int i) { try { methodInterceptor.intercept(this, save1, new Object[]{i}, null); } catch (Throwable e) { throw new RuntimeException(e); } } @Override public void save(long l) { try { methodInterceptor.intercept(this, save2, new Object[]{l}, null); } catch (Throwable e) { throw new RuntimeException(e); } } } //- 测试类 public class ProxyTest { public static void main(String[] args) { Target target = new Target(); Proxy proxy = new Proxy(); proxy.setMethodInterceptor((obj, method, args1, proxy1) -> { System.out.println("before----"); return method.invoke(target, args1); }); proxy.save(); proxy.save(1); proxy.save(2L); } }
methodProxy 不经过反射调用方法的原理
在在上述 Proxy 类中,重写了父类中的方法,并在重写的方法中调用了 intercept() 方法,重写的这些方法相当于是带增强功能的方法。
在 JDK 的动态代理中,使用反射对方法进行调用,而在 CGLib 动态代理中,可以使用 intercept() 方法中 MethodProxy 类型的参数实现不经过反射来调用方法。
接收的 MethodProxy 类型的参数可以像 Method 类型的参数一样,在静态代码块中被实例化。
public class Proxy extends Target{ private MethodInterceptor methodInterceptor; public void setMethodInterceptor(MethodInterceptor methodInterceptor) { this.methodInterceptor = methodInterceptor; } static Method save0; static Method save1; static Method save2; static MethodProxy save0Proxy; static MethodProxy save1Proxy; static MethodProxy save2Proxy; static { try { save0 = Target.class.getMethod("save"); save1 = Target.class.getMethod("save", int.class); save2 = Target.class.getMethod("save", long.class); save0Proxy = MethodProxy.create(Target.class, Proxy.class, "()V", "save", "saveSuper"); save1Proxy = MethodProxy.create(Target.class, Proxy.class, "(I)V", "save", "saveSuper"); save2Proxy = MethodProxy.create(Target.class, Proxy.class, "(J)V", "save", "saveSuper"); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } } // >>>>>>>>>>>>>>>>>>>>>>>> 带原始功能的方法 public void saveSuper() { super.save(); } public void saveSuper(int i) { super.save(i); } public void saveSuper(long i) { super.save(i); } // >>>>>>>>>>>>>>>>>>>>>>>> 带增强功能的方法 @Override public void save() { try { methodInterceptor.intercept(this, save0, new Object[0], save0Proxy); } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } @Override public void save(int i) { try { methodInterceptor.intercept(this, save1, new Object[]{i}, save1Proxy); } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } @Override public void save(long i) { try { methodInterceptor.intercept(this, save2, new Object[]{i}, save2Proxy); } catch (Throwable e) { throw new UndeclaredThrowableException(e); } } } //- 测试类 public class ProxyTest { public static void main(String[] args) { Target target = new Target(); Proxy proxy = new Proxy(); proxy.setMethodInterceptor((obj, method, args1, methodProxy) -> { System.out.println("before----"); // return method.invoke(target, args1); // return methodProxy.invoke(target, args1); // 内部无反射调用 结合目标对象使用 return methodProxy.invokeSuper(obj, args1); // 内部无反射调用, 结合代理对象使用 }); proxy.save(); proxy.save(1); proxy.save(2L); } }
MethodProxy原理
其内部是通过一个 FastClass+ 方法签名实现
模拟 结合目标对象使用
Target target = new Target(); Target proxy = (Target) Enhancer.create(Target.class, (MethodInterceptor) (obj, method, args, methodProxy) -> { System.out.println("before..."); // 内部没使用反射,需要目标(spring 的选择) Object result = methodProxy.invoke(target, args); System.out.println("after..."); return result; }); package com.example.proxy; import org.springframework.cglib.core.Signature; public class TargetFastClass { static Signature s0 = new Signature("save", "()V"); static Signature s1 = new Signature("save", "(I)V"); static Signature s2 = new Signature("save", "(J)V"); /** * <p>获取目标方法的编号</p> * <p> * Target 目标类中的方法: * save() 0 * save(int) 1 * save(long) 2 * </p> * * @param signature 包含方法名称、参数返回值 * @return 方法编号 */ public int getIndex(Signature signature) { if (s0.equals(signature)) { return 0; } if (s1.equals(signature)) { return 1; } if (s2.equals(signature)) { return 2; } return -1; } /** * 根据 getIndex() 方法返回的方法编号正常调用目标对象方法 * * @param index 方法编号 * @param target 目标对象 * @param args 调用目标对象方法需要的参数 * @return 方法返回结果 */ public Object invoke(int index, Object target, Object[] args) { if (index == 0) { ((Target) target).save(); return null; } if (index == 1) { ((Target) target).save((int) args[0]); return null; } if (index == 2) { ((Target) target).save((long) args[0]); return null; } throw new RuntimeException("无此方法"); } public static void main(String[] args) { TargetFastClass fastClass = new TargetFastClass(); int index = fastClass.getIndex(new Signature("save", "()V")); fastClass.invoke(index, new Target(), new Object[0]); index = fastClass.getIndex(new Signature("save", "(J)V")); fastClass.invoke(index, new Target(), new Object[]{2L}); } }
模拟结合 代理对象使用
Target proxy = (Target) Enhancer.create(Target.class, (MethodInterceptor) (obj, method, args, methodProxy) -> { System.out.println("before..."); // 内部没使用反射,需要代理 Object result = methodProxy.invokeSuper(obj, args); System.out.println("after..."); return result; }); package com.example.proxy; import org.springframework.cglib.core.Signature; public class ProxyFastClass { static Signature s0 = new Signature("saveSuper", "()V"); static Signature s1 = new Signature("saveSuper", "(I)V"); static Signature s2 = new Signature("saveSuper", "(J)V"); /** * <p>获取代理方法的编号</p> * <p> * Proxy 代理类中的方法: * saveSuper() 0 * saveSuper(int) 1 * saveSuper(long) 2 * </p> * * @param signature 包含方法名称、参数返回值 * @return 方法编号 */ public int getIndex(Signature signature) { if (s0.equals(signature)) { return 0; } if (s1.equals(signature)) { return 1; } if (s2.equals(signature)) { return 2; } return -1; } /** * 根据 getIndex() 方法返回的方法编号正常调用代理对象中带原始功能的方法 * * @param index 方法编号 * @param proxy 代理对象 * @param args 调用方法需要的参数 * @return 方法返回结果 */ public Object invoke(int index, Object proxy, Object[] args) { if (index == 0) { ((Proxy) proxy).saveSuper(); return null; } if (index == 1) { ((Proxy) proxy).saveSuper((int) args[0]); return null; } if (index == 2) { ((Proxy) proxy).saveSuper((long) args[0]); return null; } throw new RuntimeException("无此方法"); } public static void main(String[] args) { ProxyFastClass fastClass = new ProxyFastClass(); int index = fastClass.getIndex(new Signature("saveSuper", "()V")); fastClass.invoke(index, new Proxy(), new Object[0]); int index1 = fastClass.getIndex(new Signature("saveSuper", "(J)V")); fastClass.invoke(index1, new Proxy(), new Object[]{2L}); } }