从代理模式到Java动态代理

在之前的设计模式博文《设计模式_代理模式(Java)》中,介绍了代理模式。它是为了提供额外的操作,而创建的用来替代实际对象的对象,原理和实现都较为简单,在这篇文章中我们主要是介绍Java中提供的动态代理。

动态代理比代理的思想更向前迈进一步,因为它可以动态地创建代理,并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器(InvocationHandler实现)上。在Java中,动态代理是通过反射机制进行实现的。

下面我们来逐步分析一下Java动态代理的具体实现:

/**目标接口**/
interface Driver{
    /**目标方法**/
    public void run();
    public void stop(String c);
}
/**目标对象**/
class RealDriver implements Driver{
    public void run() {
        System.out.println("car is running"); 
    }
    public void stop(String c) {
        if(c.equals("girls")){
            System.out.println("car is stopping");
        }
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 动态代理处理器
 * 在动态代理上所做的所有调用都会被重定向到该处理器
 **/
public class DynamicProxyHandler implements InvocationHandler{
    public Object target;
    public DynamicProxyHandler(Object o){
        this.target=o;
    }
    /**
     * 执行目标对象的方法
     * proxy: 代理对象被传递进来
     * method: 被调用方法
     * args: 方法参数
     ***/
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //转调之前处理
        System.out.println("dididi~~~");
        //转调具体目标对象的方法
        Object o=method.invoke(target, args);
        //转调之后处理
        if(args!=null){
            for(Object arg:args){
                System.out.println(arg +" follow me, let's go!");
            }
        }
        return o;
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**测试类**/
public class Test {
    public static void main(String[] args) {
        //目标对象实例化
        Driver driver=new RealDriver();
        //创建处理器对象
        InvocationHandler invocationHandler=new DynamicProxyHandler(driver);
        /**
         * 获取目标对象的代理对象
         * !重点语句
         * driver.getClass().getClassLoader() 获取目标对象的类加载器
         * driver.getClass().getInterfaces() 获取目标对象的接口,或者是接口的列表,
         * 但不可以是类和抽象类,原因是动态生成的代理对象已经继承了Proxy类,无法继承其他类或者抽象类(Java单继承)
         * invocationHandler 处理器对象
         **/
        Driver driverProxy=(Driver)Proxy.newProxyInstance(driver.getClass().getClassLoader(), driver.getClass().getInterfaces(), invocationHandler);
        //调用代理对象方法
        driverProxy.run();
        driverProxy.stop("girls");
        driverProxy.stop("ladys");
    }
}

执行结果如下:

dididi~~~
car is running
dididi~~~
car is stopping
girls follow me, let's go!
dididi~~~
ladys follow me, let's go!

Spring的AOP实现其实也是通过这种方法进行的。

大家应该都注意到了再上述实现中的一些重点部分。一个是DynamicProxyHandlerinvoke()方法中的Object o=method.invoke(target, args); 它将请求转发给被代理的对象target。另一个是main()方法中的Driver driverProxy=(Driver)Proxy.newProxyInstance(driver.getClass().getClassLoader(), driver.getClass().getInterfaces(), invocationHandler); 具体参数的意义我们已经在代码注释中给出,我们重点分析Proxy.newProxyInstance() 中发生的事情,在Proxy.newProxyInstance() 中主要执行了以下三步:

//获取代理对象引用
1. Class cl = getProxyClass(loader, interfaces);
//通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
2. Constructor cons = cl.getConstructor(new Class[]{InvocationHandler.class});  
//返回代理对象,h为invocationHandler
3. return (Object) cons.newInstance(new Object[] { h });  

生成的“driverProxy”继承了Proxy类并实现了Driver目标接口,代理调用的方法实际调用处理器的invoke()方法,而invoke()方法利用反射调用的是被代理对象的的方法。

感觉比较神奇,是吧。但是Java中实现的动态代理仍存在问题,例如必须要求目标对象拥有其目标接口,否则无法实现代理,那么很多场景下可能无法实现动态代理。cglib动态代理则解除了这种限制,并且有着较高的执行效率,我们在这里就不对cglib动态代理进行介绍了,想了解的同学可以移步《Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)》进行学习。

参考:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章