代理模式
Proxy Pattern's 3 roles:
1. (abstract common)Subject:common interface
2. ProxySubject:含有the reference to the RealSubject //delegation
3. RealSubject:实现逻辑的类
类图如下:
图1
Java 动态代理
从JDK1.3开始,Java就引入了动态代理的概念。动态代理(Dynamic Proxy)可以帮助你减少代码行数,真正提高代码的可复用度。
类图如下:
图2
动态代理和普通的代理模式的区别,就是动态代理中的代理类是由java.lang.reflect.Proxy类在运行期时根据接口定义,采用Java反射功能动态生成的(图2的匿名实现类)。和java.lang.reflect.InvocationHandler结合,可以加强现有类的方法实现。如图2,图中的自定义Handler实现InvocationHandler接口,自定义Handler实例化时,将实现类传入自定义Handler对象。自定义Handler需要实现invoke方法,该方法可以使用Java反射调用实现类的实现的方法,同时当然可以实现其他功能,例如在调用实现类方法前后加入Log。而Proxy类根据Handler和需要代理的接口动态生成一个接口实现类的对象。当用户调用这个动态生成的实现类时,实际上是调用了自定义Handler的invoke方法。
下面是使用动态代理的步骤:
1. Client向Proxy请求一个具有某个功能的实例;
2. Proxy根据Subject,以自定义Handler创建一个匿名内部类,并返回给Client;
3. Client获取该匿名内部类的引用,调用在Subject接口种定义的方法;
4. 匿名内部类将对方法的调用转换为对自定义Handler中invoke方法的调用
5. invoke方法根据一些规则做处理,如记录log,然后调用SubjectImpl中的方法
Examples
Here is a simple example that prints out a message before and after a method invocation on an object that implements an arbitrary list of interfaces:
public interface Foo {Object bar(Object obj) throws BazException;}public class FooImpl implements Foo {Object bar(Object obj) throws BazException {// ...}}public class DebugProxy implements java.lang.reflect.InvocationHandler {private Object obj;public static Object newInstance(Object obj) {return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),new DebugProxy(obj));}private DebugProxy(Object obj) {this.obj = obj;}public Object invoke(Object proxy, Method m, Object[] args)throws Throwable{Object result;try {System.out.println("before method " + m.getName());result = m.invoke(obj, args);} catch (InvocationTargetException e) {throw e.getTargetException();} catch (Exception e) {throw new RuntimeException("unexpected invocation exception: " +e.getMessage());} finally {System.out.println("after method " + m.getName());}return result;}}
To construct a DebugProxy
for an implementation of the Foo
interface and call one of its methods:
Foo foo = (Foo) DebugProxy.newInstance(new FooImpl());foo.bar(null);