代理模式
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);