1 模拟Proxy模式 代理模式支持将某些操作从实际的对象中分离出来,通过它的代理类提供处理。这样便于修改和管理这些特定的操作。 下面示例一个代理模式的实现。 1.1 接口定义 package com.zj.proxy; public interface Subject { void operation1(); void operation2(String arg); } 1.2 接口实现 RealSubject.java package com.zj.proxy; public class RealSubject implements Subject { public void operation1() { System.out.println("Realer do operation1"); } public void operation2(String arg) { System.out.println("Realer do operation2 with " + arg); } } 1.3 实现代理 package com.zj.proxy; public class ProxySubject implements Subject { private Subject proxied;// 被代理对象 public ProxySubject(Subject proxied) { this.proxied = proxied; } public void operation1() { System.out.println("Proxyer do operation1"); proxied.operation1(); } public void operation2(String arg) { System.out.println("Proxyer do operation2 with " + arg); proxied.operation2(arg); } } 1.4 代理调用 package com.zj.proxy.client; import com.zj.proxy.Subject; import com.zj.proxy.RealSubject; import com.zj.proxy.ProxySubject; public class SimpleProxyDemo { public static void consumer(Subject subject) { subject.operation1(); subject.operation2("ZJ"); } public static void main(String[] args) { RealSubject real = new RealSubject(); System.out.println("===Without Proxy==="); consumer(real); System.out.println("===Use Proxy==="); consumer(new ProxySubject(real)); }} 2 动态代理机制设计 一个类用于实现InvocationHandle接口,InvocationHandler 是代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。 2.1 动态接口InvocationHandle.java package java.lang.reflect; public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } 对应invoke参数: [1]proxy - 在其上调用方法的代理实例; [2]method - 对应于在代理实例上调用的接口方法的 Method 实例; [3]args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。 2.2 实现动态接口的类 现在设计一个类实现该接口,并提供代理实例。 package com.zj.proxy.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicProxyHandler implements InvocationHandler { private Object proxied; public DynamicProxyHandler(Object proxied) { this.proxied = proxied; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("**** proxy: ****\n" + proxy.getClass() + "\nmethod: " + method + "\nargs: " + args); if (args != null) for (Object arg : args) System.out.println(" " + arg); return method.invoke(proxied, args); } } 这里的private Object proxied;即代理实例,也即上文代理模式中介绍的RealSubject对象。在invoke()方法中,我们会打印它的所有参数,并调用当前代理的方法。 2.3 代理测试类 package com.zj.proxy.client; import java.lang.reflect.Proxy;import com.zj.proxy.Subject; import com.zj.proxy.RealSubject; import com.zj.proxy.dynamic.DynamicProxyHandler; public class DynamicProxyDemo { public static void consumer(Subject subject) { subject.operation1(); subject.operation2("ZJ"); } public static void main(String[] args) { RealSubject real = new RealSubject(); System.out.println("===Without Proxy==="); consumer(real); System.out.println("===Use Proxy==="); Subject proxy = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[] { Subject.class }, new DynamicProxyHandler(real)); consumer(proxy); } } 这里通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)生成代理类,并传递与其关联的调用处理程序new DynamicProxyHandler(real)。 对于newProxyInstance()的参数: [1]loader - 定义代理类的类加载器; [2]interfaces - 代理类要实现的接口列表; [3]h - 指派方法调用的调用处理程序。 从结果可以发现,通过代理可以得到当前被调用的方法,及其参数。代理过程可以基于此进行逻辑处理,测试程序只是简单的打印这些相关信息。 3 动态代理机制的分析 3.1 传统基于接口实现扩展 调用端代理不变,通过参数改变,实现功能的改变 3.1.1 接口定义 public interface Car { public void description(); } 3.1.2 接口实现 public class BigCar implements Car { public void description() { System.out.println("BigCar"); } } 3.1.3 接口调用 Car car = new BigCar(); car.description(); 3.2 基于代理的调用扩展 3.2.1 实现代理接口 如果我们要用Proxy来做,首先需要一个实现了InvocationHandler的代理类: import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class CarProxy implements InvocationHandler { private Object delegate; public Object newInstance(Object delegate) { this.delegate = delegate; return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(delegate, args); } } 3.2.2 接口调用 CarProxy cp = new CarProxy(); Car car = (Car) cp.newInstance(BigCar.class.newInstance()); car.description(); 3.2.3 作用分析 使用Proxy一般目的有两个: (1) 一是为了在程序逻辑执行时插入其它逻辑(比如添加日志或是改写参数传递); (2) 二是为了改变程序逻辑。 3.3 基于代理的插入逻辑 3.3.1 实现代理接口 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class CarProxy implements InvocationHandler { private Object delegate; public Object newInstance(Object delegate) { this.delegate = delegate; return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) { System.out.println("before method: " + method.getName()); Object returnObj = null; try { returnObj = method.invoke(delegate, args); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } finally { System.out.println("after method: " + method.getName()); } return returnObj; } } 3.3.2 接口调用 CarProxy cp = new CarProxy(); Car car = (Car) cp.newInstance(BigCar.class.newInstance()); car.description(); 3.4 基于代理的改变逻辑 3.4.1 实现代理接口 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class CarProxy implements InvocationHandler { private Object delegate; public Object newInstance(Object delegate) { this.delegate = delegate; return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) { if (method.getName().equals("description")) { System.out.println("Caught by proxy."); } return null; } } 3.4.2 接口调用 CarProxy cp = new CarProxy(); Car car = (Car) cp.newInstance(BigCar.class.newInstance()); car.description(); 4 一个代理可以代理多个类 4.1 接口定义 4.1.1 接口一 public interface Flavor { public void taste(); } public class Spicy implements Flavor { public void taste() { System.out.println("Spicy"); } } 4.1.2 接口二 public interface Color { public void show(); } public class Red implements Color { public void show() { System.out.println("Red"); } } 4.2 代理多个类实现 import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class MultipleProxy implements InvocationHandler { private Class[] interfaces; private Object[] delegates; public MultipleProxy(Class[] interfaces, Object[] delegates) { this.interfaces = (Class[]) interfaces.clone(); this.delegates = (Object[]) delegates.clone(); } public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { Class declaringClass = m.getDeclaringClass(); for (int i = 0; i < interfaces.length; i++) { if (declaringClass.isAssignableFrom(interfaces[i])) { try { return m.invoke(delegates[i], args); } catch (InvocationTargetException e) { throw e.getTargetException(); } } } return methodNotFound(proxy, m, args); } protected Object methodNotFound(Object proxy, Method m, Object[] args) throws Throwable { throw new InternalError("unexpected method dispatched: " + m); } } 4.3 代理调用 Class[] proxyInterfaces = new Class[]{Color.class, Flavor.class}; Object obj = Proxy.newProxyInstance(Color.class.getClassLoader(), proxyInterfaces, new MultipleProxy(proxyInterfaces, new Object[]{new Red(), new Spicy()})); //3个参数:装载工具、接口类集、实现类(接口类集、接口实现类) Color color = (Color) obj; color.show(); Flavor flavor = (Flavor) obj; flavor.taste(); 顶 (责任编辑:IT) |