动态代理设计模式的原理:使用一个代理对象将原对象(目标对象)包装起来,然后利用该代理对象取代原对象。 任何对原对象的调用都要经过代理。代理对象决定是否以及何时将方法调用转到原对象上。
1 基于接口的动态代理 : 如 JDk 提供的代理 2 基于继承的动态代理 : 如第三方包 Cglib,javassist 动态代理
这里我们进行演示JDK 自身提供的代理:
jdk动态代理需要实现两个成员:一个是Proxy代理类,一个是InvocationHandler接口
1 JDK动态代理类 Proxy : 所有动态代理对象的父类,专门用于生成代理类对象或者代理对象 public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 2 接口 InvocationHandler 完成动态代理的整个过程(动态代理类的调用处理程序都必须实现InvocationHandler接口) proxy : 动态代理对象 method : 正在被调用的方法对象 args : 正在被调用的方法参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
接口和实现方法
public interface Arithmetic { public int add(int a,int b ); public int mul(int a,int b ); } public class ArithmeticImpl implements Arithmetic { @Override public int add(int a, int b) { return a + b; } @Override public int mul(int a, int b) { return a * b; } }
代理对象
/** 生成代理对象 **/ public class ProxyObject { //目标对象 private Object target; public ProxyObject(Object target) { this.target = target; } //获取代理对象 public Object getProxy(){ //代理对象 Object proxy = null; /* ClassLoader loader : 目标对象的类加载器 Class<?>[] interfaces : 接口们,目标对象提供的所有接口对象 InvocationHandler h : 代理类的调用处理对象需要实现的接口 */ ClassLoader loader = target.getClass().getClassLoader(); Class<?>[] interfaces = target.getClass().getInterfaces(); InvocationHandler h = new MyInvocationHandler(target); //这里创建代理对象,使得代理对象和目标对象拥有相同的方法行为,h是代理对象调用处理执行的方法。 proxy = Proxy.newProxyInstance(loader,interfaces,h); return proxy; } } class MyInvocationHandler implements InvocationHandler{ private Object target; public MyInvocationHandler(Object target) { this.target = target; } //代理对象调用代理方法,会回来调用 invoke 方法 // proxy 代理对象 ,一般不会使用 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(" 动态代理对象 : " + proxy.getClass()); System.out.println(" 正在被调用的方法方法对象 : " + method); System.out.println(" 正在被调用的方法方法名 : " + method.getName()); System.out.println(" 正在被调用的方法参数 : " + Arrays.asList(args)); System.out.println("执行方法前 "); //实际上是内部在这儿使用目标对象执行目标方法。 Object result = method.invoke(target,args); //目标对象,调用目标方法 相当于 ArithmeticImpl调用自己的方法 System.out.println("执行方法后 result = " + result); return result; } }
测试
public static void main(String[] args) { //目标对象 Arithmetic target = new ArithmeticImpl(); //获取代理对象 Object object = new ProxyObject(target).getProxy(); Arithmetic proxyObject = (Arithmetic) object; proxyObject.add(1,2); }
结果
动态代理对象 : class com.sun.proxy.$Proxy0 正在被调用的方法方法对象 : public abstract int com.example.demo.service.Arithmetic.add(int,int) 正在被调用的方法方法名 : add 正在被调用的方法参数 : [1, 2] 执行方法前 执行方法后 result = 3
$Proxy0 就是我们的动态代理对象
可以在main方法中添加一行代码将代理的对象字节码打印出来!
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class<?>[]{Arithmetic.class}); try { String pathDir = "E://"; String path = "//$Proxy0.class"; File f = new File(pathDir); if (!f.exists()) { f.mkdir(); } path = f.getAbsolutePath() + path; f = new File(path); if (f.exists()) { f.delete(); } f.createNewFile(); try (FileOutputStream fos = new FileOutputStream(path)) { fos.write(bytes); } catch (Exception e) { e.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); }
反编译后 $Proxy0 代码
import com.example.demo.service.Arithmetic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements Arithmetic { private static Method m1; private static Method m2; private static Method m4; private static Method m3; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) throws { //调用父类Proxy 设置 InvocationHandler 代理对象处理器,设置调用代理方法 h super(paramInvocationHandler); } public final boolean equals(Object paramObject) throws { try { //判断需要代理的方法 return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String toString() throws { try { return (String)this.h.invoke(this, m2, null); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int mul(int paramInt1, int paramInt2) throws { try { //处理调用 invoke方法, this 当前代理对象 return ((Integer)this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt1), Integer.valueOf(paramInt2) })).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int add(int paramInt1, int paramInt2) throws { try { return ((Integer)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt1), Integer.valueOf(paramInt2) })).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final int hashCode() throws { try { return ((Integer)this.h.invoke(this, m0, null)).intValue(); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { //判断 是否是对象的方法 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m4 = Class.forName("com.example.demo.service.Arithmetic").getMethod("mul", new Class[] { Integer.TYPE, Integer.TYPE }); m3 = Class.forName("com.example.demo.service.Arithmetic").getMethod("add", new Class[] { Integer.TYPE, Integer.TYPE }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } }
通过代理对象源码可以看到
初始化 h
public $Proxy0(InvocationHandler paramInvocationHandler) throws { //调用父类Proxy 设置 InvocationHandler 代理对象处理器,设置调用代理方法 h super(paramInvocationHandler); }
底层调用
return ((Integer)this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt1),
这行代码实际上是通过invoke 调用当前 原目标方法对象 以及参数,也就是我们写的 MyInvocationHandler 类中 invoke 方法。
关于 InvocationHandler 接口中invocation方法中第一个参数proxy说明。
proxy参数表示的是代理对象,那这个参数有何意义呢, 什么时候去使用呢,为什么这里没有使用这个参数呢。
看了很多博客感觉 描述不清,众说纷纭。
jdk中直接这么描述:
the proxy instance that the method was invoked on
一般常用后面两个参数,第一个是代理对象,一般方法中没有用到!