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();