加入收藏 | 设为首页 | 会员中心 | 我要投稿 开发网_开封站长网 (http://www.0378zz.com/)- 科技、AI行业应用、媒体智能、低代码、办公协同!
当前位置: 首页 > 教程 > 正文

Java InvocationHandler 与 Proxy 动态代理介绍

发布时间:2021-11-12 10:20:07 所属栏目:教程 来源:互联网
导读:Proxy 类 Proxy 类的 newProxyInstance 方法返回一个代理对象: public static Object newProxyInstance(ClassLoader loader, Class?[] interfaces, InvocationHandler h) throws IllegalArgumentException loader :一个类加载器,用 null 表示使用默认的类

Proxy 类
Proxy 类的 newProxyInstance 方法返回一个代理对象:
 
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
loader :一个类加载器,用 null 表示使用默认的类加载器。
interfaces :一个 Class 对象数组,每个元素都是需要实现的接口。
h :一个调用处理器。
另外两个方法:
 
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) :返回指定接口的代理类。
public static boolean isProxyClass(Class<?> cl) :如果 cl 是一个代理类则返回 true。
InvocationHandler 接口
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 Java.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
Tips
代理类在跟踪方法调用时很有用,比如我们可以为 Comparable 接口创建代理类,在compareTo 方法调用之前,打印出一些信息,这样一来,就可以查看到排序时比较的过程。

(编辑:开发网_开封站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读