(十五)代理
代理模式的作用
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式一般涉及到的角色
抽象角色:声明真实对象和代理对象的共同接口;
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
动态代理
Java中动态代理机制的引入使得代理模式的思想更加完善与进步,它允许动态的创建代理并支持对动态的对所代理的方法进行调用。Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
Interface InvocationHandler
该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。
Proxy
该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:
Protected Proxy(InvocationHandler h)
构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces)
获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。 下面我们通过动态代理来发送信息的例子!
先添加一个通过短信来发送消息的处理类:
//接口定义 public interface MessageHandler { public void sendMessage(String msg); } public class SmsMessage implements MessageHandler { @Override public void sendMessage(String msg) { // TODO Auto-generated method stub System.out.println("SMS Message :" + msg+" sent !"); } } //动态代理类 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicMessageProxy implements InvocationHandler { private static int count; private MessageHandler msgHandler; public DynamicMessageProxy(MessageHandler handler) { msgHandler = handler; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub
System.out.println("+++++++++++++++++++++++");
System.out.println("proxy:"+proxy.getClass());
System.out.println("method:"+method);
System.out.println("-----------------------");
if(args !=null && args.length==1 ){
count++;
System.out.println("Message sent:"+count);
return method.invoke(msgHandler, args);
}
return null; } private boolean checkMessage(String msg) { return msg != null && msg.length() > 10; } } //下面是调用 import java.lang.reflect.Proxy; public class MainClass { /** * @param args */ public static void main(String[] args) { MessageHandler handler = new SmsMessage(); handler.sendMessage("message for test"); MessageHandler proxy = (MessageHandler) Proxy.newProxyInstance(MessageHandler.class .getClassLoader(), new Class[] { MessageHandler.class }, new DynamicMessageProxy(handler)); proxy.sendMessage("message for test"); } }
输出:
SMS Message:message for test!sent!
+++++++++++++++++++++++
proxy:class com.sun.proxy.$Proxy0
method:public abstract void project02.MessageHandler.sendMessage(java.lang.String)
-----------------------
Message sent:1
SMS Message:message for test!sent!
以上例子中,通过调用Proxy.newProxyInstance方法创建动态代理对象,该方法需要传入一个 类加载器、一组希望代理实现的接口列表、InvocationHandler 接口的一个具体实现。动态代理可以将所有调用重定向到调用处理器,通常我们会向该处理器传递一个时间对象的引用。invoke()方法中传递进来了代理对象,当你需要区分请求来源时这是非常有用的,例如你可以通过判断传入的方法名屏蔽掉某些方法的执行!