您的位置:首页 > 编程语言 > Java开发

《大话设计模式》读书笔记:代理模式与Java的Proxy动态代理

2016-12-15 10:07 267 查看
代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问。

在面向对象编程中,直接引用某些对象会因为种种原因(比如对象创建的开销过大,访问需要安全控制,或者需要跳出当前进程等)带来很多问题,给用户或者系统本身带来不便或者异常。这时,就需要在操作对象(客户端)和被调用对象(真实对象)之间添加一个代理,以协助操作对象控制对被调用对象的访问,起到透明中介的作用。

代理模式的应用:一是远程代理,即为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实;二是虚拟代理,即根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象;三是安全代理,用来控制真实对象访问时的权限;四是智能指引,即当调用真实对象时,代理处理另外一些事。

代理模式的实现,主要有以下几个特点:

1.      真实对象和代理对象拥有共同的父类或者实现相同的接口,实现了相同的方法;

2.      代理对象引用或者包含真实对象的一个实例,该实例在代理对象中初始化,代理对象通过1中所述的相同方法来替代对真实对象的调用;

3.      客户端中不再实例化真实对象,完全通过代理对象来访问真实对象。

 

代理模式的简单示例,参见如下地址:

http://www.cnblogs.com/kid-li/archive/2006/10/18/532192.html

顺带一提的是,百度百科“Java代理模式”词条中的代码示例实际上是装饰模式,而不是代理模式。

 

在Java中,通常使用Proxy(动态代理)来实现对代理模式的支持。动态代理的详细描述参见《Java核心技术(卷1)》6.5节·代理。

Java中要创建一个代理对象,必须调用Proxy类的静态方法newProxyInstance,该方法的原型如下:

Object  Proxy.newProxyInstance(ClassLoader  loader, Class<?>[]  interfaces, InvocationHandler  handler)  throws  IllegalArgumentException

其中:

loader,表示类加载器,对于不同来源(系统库或网络等)的类需要不同的类加载器来加载,这是Java安全模型的一部分。可以使用null来使用默认的加载器;

interfaces,表示接口或对象的数组,它就是前述代理对象和真实对象都必须共有的父类或者接口;

handler,表示调用处理器,它必须是实现了InvocationHandler接口的对象,其作用是定义代理对象中需要执行的具体操作。

 

InvocationHandler之于Proxy,就如Runnable之于Thread。InvocationHandler接口中只有一个方法invoke,它的作用就跟Runnable中的run方法类似,定义了代理对象在执行真实对象的方法时所希望执行的动作。其原型如下:

Object  invoke(Object  proxy, Method  method, Object[]  args)  throws  Throwable

其中:

proxy,表示执行这个方法的代理对象;

method,表示真实对象实际需要执行的方法(关于Method类参见Java的反射机制);

args,表示真实对象实际执行方法时所需的参数。

 

在实际的编程中,需要优先定义一个实现InvocationHandler接口的调用处理器对象,然后将它作为创建代理类实例的参数。(抑或在调用newProxyInstance方法时使用匿名内部类。)这样就得到了代理对象。

真实对象本身的实例化在调用处理器对象内部完成,实例化时需要的参数也应该及时传入调用处理器对象中。这样一来就完成了代理对象对真实对象的包装,而代理对象需要执行的额外操作也在invoke方法中处理。

其后,在客户端中,如果需要使用真实对象时,就可以用代理对象来替代它了(有时需要类型强制转化)。

 

下面的示例用Java的动态代理模拟了一个拦截器的功能:对于实现了Action接口的类,如果类名不以Action结尾,则不予执行。

共同接口Action:

[java]
view plain
copy

public interface Action {  
    public void excute();  
}  

实现了Action接口的三个真实对象:

[java]
view plain
copy

public class FirstAction implements Action {  
  
    @Override  
    public void excute() {  
        System.out.println("This is the first action.");  
    }  
  
}  

[java]
view plain
copy

public class Second implements Action {  
  
    @Override  
    public void excute() {  
        System.out.println("This is the second action.");  
    }  
  
}  

[java]
view plain
copy

public class ThirdAction implements Action {  
  
    @Override  
    public void excute() {  
        System.out.println("This is the third action.");  
    }  
  
}  

调用处理器对象FilterHandler,它是对拦截器的实现:

[java]
view plain
copy

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
  
public class FilterHandler implements InvocationHandler {  
    private String className;  
      
    public FilterHandler(String className) {  
        this.className = className;  
    }  
  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args)  
            throws Throwable {  
        if (className.endsWith("Action")) {  
            System.out.println(className + "." + method.getName());  
            return method.invoke(Class.forName(className).newInstance(), args);  
        } else {  
            System.out.println(className + " doesn't end with 'Action'");  
            return null;  
        }  
    }  
  
}  

客户端:

[java]
view plain
copy

import java.lang.reflect.Proxy;  
  
public class Main {  
      
    public static void main(String[] args) {  
        FilterHandler handler1 = new FilterHandler("com.proxy.filter.FirstAction");  
        Action first = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class[] {Action.class}, handler1);  
          
        FilterHandler handler2 = new FilterHandler("com.proxy.filter.second");  
        Action second = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class[] {Action.class}, handler2);  
          
        FilterHandler handler3 = new FilterHandler("com.proxy.filter.ThirdAction");  
        Action third = (Action) Proxy.newProxyInstance(Action.class.getClassLoader(), new Class[] {Action.class}, handler3);  
          
        first.excute();  
        second.excute();  
        third.excute();  
    }  
}  

最后需要特别说明的是:

1.      Proxy创建的代理对象实例包含Object类中的全部方法和接口数组(即newProxyInstance方法中的interfaces参数)中的全部方法。但是,代理类会覆盖Object类中的toString、equals和hashCode方法,而clone、getClass等方法则没有重新定义。另外,所有这些方法都需要在InvocationHandler的invoke方法中通过调用Method对象的invoke方法才能真正被执行。

2.      对于特定的类加载器和预设的一组接口来说,即便是调用处理器handler不一样,也只能得到同一个代理类。也就是说,示例中三次对newProxyInstance方法的调用,其实只是得到的同一个对象的三个实例而已,并不是三种不同的类。

其它Java动态代理的细节参见《Java核心技术》或Java
API。

原文出处:http://blog.csdn.net/sadfishsc/article/details/7312253
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  设计模式