java(15): 动态代理模式解析

首先看一下 java 中的动态代理类:

1. Java 动态代理类位于 java.lang.reflect 包下,一般主要涉及到以下两个类:

a. Interface InvocationHandler:该接口中仅定义了一个方法(该方法在代理类中动态实现):

/*
* 第一个参数 proxy 是代理类;第二个参数 method 是被代理的方法; 第三个是该代理方法的参数数组。
*/
public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable;

b. Proxy:动态代理类。作用类似于前面说的静态代理模式中的 ProxySubject 类。

/*
*  构造方法,用于给内部的 h 赋值
*/
protected Proxy(InvocationHandler h) {
    Objects.requireNonNull(h);
    this.h = h;
}



/*
 * 获得一个代理类。其中 loader 是类加载器,interfaces 是真实类所拥有的全部接口的数组
 */
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces){
    ...
}

/*
 * 返回代理类的一个实例。返回后的代理类可以当作真实类使用(可使用真实类在 Subject  接口中声明过的方法)
 * 注意,第二个参数 Interfaces 是真实对象中实现的接口 Class 对象数组
 */
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {
    ...
}

2. 所谓的 Dynamic Proxy 是这样一种 class: 它是在运行时生成的类,在生成它时你必须提供一组 Interface 给它,然后该类就宣称它实现了这些 Interface。你当然可以把该类的实例当作这些 Interface 中的任何一个来使用(多态)。当然,这个 Dynamic Proxy 其实就是一个 Proxy,它不会替你做实质性的工作,在生成它的实例时你必须提供一个 Handler(也就是 invocationHandler 实例对象),由它来接管实际的工作。

 

3. 在使用动态代理类时,我们必须实现 InvocationHandler 接口。

eg:

// 抽象角色
public interface Subject {
    void request();
}
// 真实角色
public class RealSubject implements Subject {

    @Override
    public void request() {
        System.out.println("From real subject!");
    }
}
/**

* 该代理类的内部属性是 Object 类型,实际使用的时候通过该类的构造方法传递进来一个对象。此外,该类还实现了
* InvocationHandler 接口中的 invoke() 方法,该方法中的 method.invoke() 其实就是调用被代理对象要执行的方法,
* 方法参数是 sub,表示该方法从属于 sub 对象,通过动态代理类,我们可以在执行真实对象的方法前后加入自己的一
* 些额外方法。这样我们就可以通过这一个代理类代理任何一个真实角色对象。
*/
public class DynamicSubject implements InvocationHandler {

    // 这个类可以代理任何一个真实类
    private Object sub;

    public DynamicSubject(Object obj){
        this.sub = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before calling: " + method);
        // 通过反射来完成真实对象中的方法调用(这里就是调用 sub 对象中(也就是真实角色对象)中的相应方法),后面 args 是这个方法需要的参数数组
        method.invoke(sub, args);
        System.out.println("after calling: " + method);
        return null;
    }
}
// 客户端
public static void main(String[] args) {
    // 创建一个真实角色对象
    RealSubject realSubject = new RealSubject();

    // 创建一个 InvocationHandler 接口,最后 subject.request() 方法实现实际就是调用这个对象的 invoke() 方法。
    InvocationHandler handler = new DynamicSubject(realSubject);

    // 创建 Class 对象
    Class<?> classType = handler.getClass();

    // 创建代理类对象,然后通过代理类对象调用真实角色对象的方法。
    // realSubject.getClass().getInterfaces() 就是 RealSubject 类实现的 Subject 接口的 Class 对象
    Subject subject = (Subject) Proxy.newProxyInstance(classType.getClassLoader(), realSubject.getClass().getInterfaces(), handler);
    // 这个 request() 方法就是上面第二个参数 realSubject.getClass().getInterfaces() 接口中的方法。
    subject.request();
}

// output
before calling: public abstract void com.cfm.dynamicproxy.Subject.request()
From real subject!
after calling: public abstract void com.cfm.dynamicproxy.Subject.request()

通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

总结:

1. 动态代理是指客户通过代理类来调用其它对象的方法。它使用的场合:调试、远程方法调用(RMI)等等。

2. 动态代理创建步骤:

    a. 创建一个实现接口 InvocationHandler 的类并实现它里面的 invoke() 方法。

    b. 创建被代理的类以及接口(也就是真实角色和抽象角色)。

    c. 通过 Proxy 的静态方法(如下所示),创建一个代理类。

newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

    d. 通过 c 创建的代理实例调用相应的被代理方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值