您的位置:首页 > 编程语言 > Java开发

代理模式和java动态代理的机制(一)InvocationHandler

2011-07-26 15:51 756 查看

首先回顾下Proxy模式



Provide a surrogate or palceholder for another object to control access to it.

其实就是把要控制的类包上一层。接口是一致的,所以从外面看不出区别,里面却大有乾坤。

客户类:

1 public class ProxyTest2 {
2 public static void main(String[] args) {
3 Subject subject = ProxyTest2.getASubject();
4 subject.doOperationOne();
5 }
6
7 public static Subject getASubject(){
8 RealSubject realSubject = new RealSubject();
9 return new Proxy(realSubject);
}
}

抽象主题角色

public interface Subject{
public void doOperationOne();
}

实际主题角色

public class RealSubject implements Subject{

@Override
public void doOperationOne() {
System.out.println("One~~~~~~~~~~~~~~~~~~~~~~");

}
}

代理角色

1 public class Proxy implements Subject {
2 Subject target;
3 public Proxy(Subject target){
4 this.target = target;
5 }
6
7 @Override
8 public void doOperationOne() {
9 System.out.println("befer.....");
target.doOperationOne();
System.out.println("after.....");
}
}

动态代理

java提供一个机制,可以给任意接口的实例加上一个代理。叫做动态代理。

上面这个例子的抽象主题角色和 真实主题角色保留。看看动态代理是怎么做的。

新的客户端:

1 public class ProxyTest {
2
3 public static void main(String[] args) {
4 Subject subject = ProxyTest.getASubject();
5 subject.doOperationOne();
6 }
7
8 public static Subject getASubject(){
9 RealSubject realSubject = new RealSubject();
InvocationHandler proxyImpl = new Handler(realSubject);
Subject proxy = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
proxyImpl );
return proxy;
}

}

原本代理角色的工作被移动到java.lang.reflect.InvocationHandler接口的实现里完成

1 public class Handler implements InvocationHandler {
2 Subject realSubject;
3
4 public Handler(Subject realSubject) {
5 this.realSubject = realSubject;
6 }
7
8 //
9
//
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println(method.getName() + " before...");
method.invoke(realSubject, args);
System.out.println(method.getName() + " after...");
return null;
}
}

研究下reflect.Proxy的源码看看是怎么和InvocationHandler配合实现动态代理的效果

1 public static Object newProxyInstance(ClassLoader loader,
2 Class<?>[] interfaces,
3 InvocationHandler h)
4 throws IllegalArgumentException
5 {
6 if (h == null) {
7 throw new NullPointerException();
8 }
9
/*
* Look up or generate the designated proxy class.
*/
Class cl = getProxyClass(loader, interfaces);

/*
* Invoke its constructor with the designated invocation handler.
*/
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
}
}

第十九行:根据接口产生一个类(代理?)。
第二十行:获取代理类的构造器。constructorParams是个final的Class数组 { InvocationHandler.class })
第二十一行:以传入的InvocationHandler实例为参数,实例化代理。返回。

下面看下用于生成代理类的getProxyCalss方法里核心的代码。

1 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
2 proxyName, interfaces);
3 try {
4 proxyClass = defineClass0(loader, proxyName,
5 proxyClassFile, 0, proxyClassFile.length);
6 } catch (ClassFormatError e) {
7 /*
8 * A ClassFormatError here means that (barring bugs in the
9 * proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}

红色标记出来的方法,无法看到源码。不过根据语义大致应该是自动产生一个class。

我们知道代理类实现的接口,知道代理类有一个InvocationHandler类型的成员。要生成这么一个代理类似乎也不太难。

1 import java.lang.reflect.InvocationHandler;
2 import java.lang.reflect.Method;
3
4 public class Imagined implements Subject {
5 private InvocationHandler handler;
6
7 public Imagined(InvocationHandler handler){
8 this.handler = handler;
9 }

@Override
public void doOperationOne() {
try {
Method method = Subject.class.getDeclaredMethod("doOperationOne");
System.out.println(method.getName());
handler.invoke(this, method,null);
} catch (Throwable e) {
e.printStackTrace();
}
}
}

新的客户端,验证下。

1 import java.lang.reflect.InvocationHandler;
2
3 public class ProxyTest3 {
4
5 public static void main(String[] args) {
6 Subject subject = ProxyTest3.getASubject();
7 subject.doOperationOne();
8 }
9
public static Subject getASubject(){
RealSubject realSubject = new RealSubject();
InvocationHandler handler= new Handler(realSubject);
Subject subject = new Imagined(handler);
return subject;
}

}

待续...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: