动态代理 ---jdk
我们都对静态代理比较熟悉(不熟悉自己找个例子看看就知道了)
jdk动态代理,重点就是一个。自动生成一个类的静态代理,并实例化这个自动生成的代理。
动态代理 ,就是自动生成的 代理
先上一个标准用法
接口
public interface Dog { void run(); int eatCount(); boolean eta(String name); }
实现
public class GunDog implements Dog { @Override public void run() { System.out.println("----------------飞奔"); } @Override public int eatCount() { return 5; } @Override public boolean eta(String name) { return false; } }
必不可少的 InvocationHandler 实现
public class MyInvocationHandler implements InvocationHandler { Object target; // 这个为 需要 被 代理 的对象 public void setTarget(Object target){ this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // proxy 为动态代理生产的对象 // 运行的方法 // 方法对应的参数 // 此处的逻辑完全自己掌控,经常的写法包含 写一些 逻辑 ,再 method.invoke(target , args) , 再写一下逻辑 //放回值为方法的放回,可以为 method.invoke(target , args) 的返回值 ,也可以完全 根据 自己需求来写 return null; } }
使用
public class MyProxyFactory { public static Object getProxy(Object target){ InvocationHandler invocationHandler = new MyInvocationHandler(); ((MyInvocationHandler) invocationHandler).setTarget(target); Object o = Proxy.newProxyInstance(target.getClass().getClassLoader() , target.getClass().getInterfaces() , invocationHandler); return o; } public static void main(String[] args) { Dog dog = new GunDog(); Dog proxy = (Dog) MyProxyFactory.getProxy(dog); proxy.run(); System.out.println(proxy.eatCount()==null?null:proxy.eatCount()); proxy.eta("fish"); } }
简单的说明一下把,什么是代理 和 代理模式什么的,我就不说了
就先来看一下,这个代理对象到底是怎样的
public class ZTest { public static void main(String[] args) { m1(); } public static void m1(){ byte[] proxy0s = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{Dog.class}); try (FileOutputStream fileOutputStream = new FileOutputStream("$Proxy0.class")) { fileOutputStream.write(proxy0s); fileOutputStream.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
这样会生产一个 $Proxy0.class 的文件(在哪里自己直接文件搜,不细说) 。 用itellij idea 打开 这个.class文件
import com.xsz.impl.proxy.Dog; 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 Dog { private static Method m1; private static Method m3; private static Method m4; private static Method m2; private static Method m5; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void run() throws { try { super.h.invoke(this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final boolean eta(String var1) throws { try { return (Boolean)super.h.invoke(this, m4, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } 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 Integer eatCount() throws { try { return (Integer)super.h.invoke(this, m5, (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); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.xsz.impl.proxy.Dog").getMethod("run"); m4 = Class.forName("com.xsz.impl.proxy.Dog").getMethod("eta", Class.forName("java.lang.String")); m2 = Class.forName("java.lang.Object").getMethod("toString"); m5 = Class.forName("com.xsz.impl.proxy.Dog").getMethod("eatCount"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
这个就是代理对象 反编译后 得到的java 文件的样子了 ,这个 重写 hashCode ,toString ,equals 方法,没什么好说的。
重要的点一,这个对象实现了Dog接口,且重写里面的方法 ,run ,eatCount ,eta
重要点二 ,有 Method 类型的 私有静态 变量 ,在static 构造函数中直接 赋值(赋值简单明白)
重要点三,有一个 InvocationHandler 的构造函数。
再回过头来看 Object o = Proxy.newProxyInstance(target.getClass().getClassLoader() , target.getClass().getInterfaces() , invocationHandler); 做了什么(源码)
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); final SecurityManager sm = System.getSecurityManager(); if (sm != null) { checkProxyAccess(Reflection.getCallerClass(), loader, intfs); } /* * Look up or generate the designated proxy class. */ Class<?> cl = getProxyClass0(loader, intfs); /* * Invoke its constructor with the designated invocation handler. */ try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams); final InvocationHandler ih = h; if (!Modifier.isPublic(cl.getModifiers())) { AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { cons.setAccessible(true); return null; } }); } return cons.newInstance(new Object[]{h}); } catch (IllegalAccessException|InstantiationException e) { throw new InternalError(e.toString(), e); } catch (InvocationTargetException e) { Throwable t = e.getCause(); if (t instanceof RuntimeException) { throw (RuntimeException) t; } else { throw new InternalError(t.toString(), t); } } catch (NoSuchMethodException e) { throw new InternalError(e.toString(), e); } }
简单分析(这个结合我们$Proxy0 文件看)
返回的是代理对象,代理对象进行调用时 ,如调用 proxy.eta("fish") ,实际调用参考 $Proxy0 文件
选一个方法分析。我们在看看 第二个参数 m4是什么 。
m4 为 静态私有方法,在static代码块 中 赋值。
本质, 调用 我们自己写的 InvocationHandler 中的 invoke 方法。返回结果 直接被 代理对象返回
也就是,我们可以在自己的 InvocationHandler 的invoke方法中,任意写自己的逻辑。
我个人以前也不太懂代理对象长啥样,怎么就是那样调用的,我想看了 $Proxy0 文件之后,就能一清二楚的知道整个调用逻辑了
还有一点,运行这个程序是会报错的,具体报错原因我就不细说了,反正就是直接返回null造成的
posted on 2021-03-13 12:27 xingshouzhan 阅读(79) 评论(0) 编辑 收藏 举报