jdk的动态代理是基于接口实现的,所以一定要有接口,它可以实现两个功能 1)为接口生成一个实例对象 2)为实现接口的实例对象加入切面逻辑;
假设有个MoveAble接口,意为可移动的,通过jdk的动态代理可以生成实现这个接口的实例。
jdk生成的代理实例最终会调用这个类的invoke方法,相当于写在这个处理程序实现了原本应该由MoveAble实类实现的逻辑。
public class MoveAbleHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("这边是代理做的工作"); return null; } }Proxy.newProxyInstance()方法最终会通过native方法生成代理对象
private static native Class<?> defineClass0(ClassLoader loader, String name,byte[] b, int off, int len);通过jdk的sum.misc.ProxyGenerator类可以查看生成的字节码文件,如下配置
import java.io.File; import java.io.FileOutputStream; import java.lang.reflect.Proxy; /** * Created by rongyaowen * on 2019/5/23. */ public class Test { public static void main(String[] args) throws Exception { // 第一个参数是类加载器,用来加载生成的代理类 // 第二个参数是代理类实现的接口 // 第三个参数是调用处理程序 MoveAble moveAble = (MoveAble) Proxy.newProxyInstance(MoveAble.class.getClassLoader(), new Class[]{MoveAble.class}, new MoveAbleHandler()); moveAble.move(); byte[] bts = ProxyGenerator.generateProxyClass("$MoveAble", Tank.class.getInterfaces()); FileOutputStream fos = new FileOutputStream(new File("E:/$MoveAble.class")); fos.write(bts); fos.flush(); fos.close(); } }将生成的字节码拉入idea中可以看到如下内容
import com.honor.proxy.MoveAble; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $MoveAble extends Proxy implements MoveAble { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $MoveAble(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue(); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void move() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } 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)).intValue(); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m3 = Class.forName("com.honor.proxy.MoveAble").getMethod("move", new Class[0]); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }注:重写了equals、hashCode和toString方法。重点看move方法,move方法通过反射调用了父类的invoke方法。
return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();super.h是什么呢?跟进去一看是
protected InvocationHandler h;h是什么时候赋值的呢,当生成的代理实例初始化时,会将InvocationHandler对象赋值给proxy
public $MoveAble(InvocationHandler var1) throws { super(var1); }那么初始化实例的时候传入的是什么值呢
return cons.newInstance(new Object[]{h});这个h就是newProxyInstance传入得第三个参数,是调用处理程序
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)总结:通过newProxyInstance方法会生成一个实现了接口(第二个参数)的实例对象,这个对象实现了接口的方法,调用的是调用处理程序(第三个参数)的invoke方法。
注:这边在代理执行程序中还执行了代理类的方法
Object object = method.invoke(moveAble, args);