Proxy 类的 newProxyInstance 方法返回一个代理对象:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
另外两个方法:
newProxyInstance 方法的第三个参数就是 InvocationHandler, 这个接口只有一个方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
当调用代理类的任何一个方法的时候,invoke 方法就会被先调用,method 就是原始对象的方法,args 是该方法的原始参数。
这里的第一个参数 proxy ,他是真实对象(也就是我们要代理的对象)的代理对象,它实际上就是 Proxy 的 newInstance 方法返回的那个对象。一般情况下,我们在 invoke() 方法中都是返回真实对象方法的调用结果,当我们需要对代理对象进行连续调用(链式调用)时,可以返回这个对象。
一般情况乱下(target 为真实对象):
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(target, args); }
需要连续调用时:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { method.invoke(target, args); return proxy; }
现在,创建一个 Hero 接口,它包含一个 attack() 方法,然后使用动态代理,任何实现了 Hero 接口的英雄在调用 attack 前后分别打印出“施法前摇”和“施法后摇”。
package cloud.proxy; public interface Hero { void attack(); }
再创建一个施放雷神之怒的宙斯:
package cloud.proxy; import static <a href="../../Java" target="_blank" title="https://www.linuxidc.com/topicnews.aspx?tid=19">Java</a>.lang.System.out; public class Zues implements Hero { @Override public void attack() { out.println("雷神之怒!"); } }
最后通过 HeroProxy 类来创建代理对象:
package cloud.proxy; import java.lang.reflect.Proxy; import static java.lang.System.out; public class HeroProxy { private void before() { out.println("准备施法..."); } private void after() { out.println("施法完成。"); } public Hero newInstance(final Class<? extends Hero> targetClass) throws Throwable { Hero target = targetClass.getConstructor().newInstance(); return (Hero) Proxy.newProxyInstance(Hero.class.getClassLoader(), new Class[]{Hero.class}, (proxy, method, args) -> { before(); Object result = method.invoke(target, args); after(); return result; } ); } }
当调用 HeroProxy 的 newInstance() 方法时,创建了原始对象 target,然后通过 Proxy 类来获取代理对象,这里没有创建实体类实现 InvocationHandler,而是直接使用了匿名类(lambda表达式)。
测试类:
package cloud.proxy; import org.junit.Test; public class HeroProxyTest { @Test public void getProxyObject() throws Throwable { HeroProxy proxy = new HeroProxy(); // 创建 Zues 的代理对象 Hero hero = proxy.newInstance(Zues.class); hero.attack(); } }
执行结果:
com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 -junit4 cloud.proxy.HeroProxyTest 准备施法... 雷神之怒! 施法完成。 Process finished with exit code 0
代理类在跟踪方法调用时很有用,比如我们可以为 Comparable 接口创建代理类,在compareTo 方法调用之前,打印出一些信息,这样一来,就可以查看到排序时比较的过程。
Linux公社的RSS地址 : https://www.linuxidc.com/rssFeed.aspx
本文永久更新链接地址: https://www.linuxidc.com/Linux/2019-08/160011.htm