您的位置:首页 > 其它

设计模式(9)--Proxy代理模式

2016-02-16 17:27 447 查看
代理模式是一个很重要的模式,因为大名鼎鼎的AOP,以及Webservice等都与代理模式有关系。代理模式的实质,是通过代理类来隐藏实际类(或者叫委托类),从而控制实际对象的访问。代理模式的用处,可以用来封装webservice形式的远程地址调用;可以用来预置对象的外观,避免直接加载大对象的耗时(有兴趣可以仔细研究浏览器代理);可以用于权限安全控制;再就是AOP切面增强。

PS:WebService我们一般在用工具创建时就会产生代理类。但实际上我们不是一定要使用代理类,直接使用底层的远程url访问等代码也可以使用。但是代理类相当于屏蔽了细节,使用方便,更易控制。

代理模式本身并不难理解,直接上图:



1.抽取接口并定义方法,委托类(RealSubject)和代理类(Proxy)都必须实现这个接口的方法。

2.代理类中需要有委托类成员对象,并在接口方法的实现中代用委托类的方法实现,在调用前后,可自由加入自己的代理逻辑。

3.应结合工厂模式完成代理对象的创建。客户端从工厂中得到的是Subject接口,根本不知道是真实对象还是代理对象,至此,代理完成。

所谓静态代理,包括代理增强逻辑在内的代码全部都已经在编译时写好,可以直接运行。但是静态代理的缺陷显而易见,像Spring AOP,众多的切面增强,都是灵活配置的。在运行前无法得知哪些对象,哪些方法要代理,要进行哪些增强,所以必须使用动态代理。

动态代理:实际上Java本身已经提供了动态代理框架,核心思想是利用反射,可以在运行时去动态的创建代理对象并执行委托对象的方法。

a.java.lang.Proxy,是所有动态代理类的父类,他是专门用来生成实际使用的代理类对象的。

//指定类装载器、一组接口以及调用处理器生成动态代理类实例
public static Object newProxyInstance(ClassLoader paramClassLoader, Class<?>[] paramArrayOfClass, InvocationHandler paramInvocationHandler) throws IllegalArgumentException {
if (paramInvocationHandler == null) {
throw new NullPointerException();
}
//paramClassLoader是委托类对象的类装载器,paramArrayOfClass为委托类对象对应的一组接口
Class localClass = getProxyClass(paramClassLoader, paramArrayOfClass);
try
{
Constructor localConstructor =localClass.getConstructor(constructorParams);
return localConstructor.newInstance(new Object[] { paramInvocationHandler });
...


b.InvocationHandler,成为动态代理处理类。在java的动态代理框架中,这也是代理类对象必须实现的接口,最终的方法调用实际上是调用invoke方法。

注意在实现该处理类时,必须为处理类指定委托对象,并在invoke方法中使用委托对象的反射去执行相关方法。

package java.lang.reflect;
public abstract interface InvocationHandler
{
public abstract Object invoke(Object paramObject, Method paramMethod, Object[] paramArrayOfObject)
throws Throwable;
}

public class SubjectInvocationHandler implements InvocationHandler {

//代理类持有一个委托类的对象引用,注意是Object,才能支持动态
private Object delegate;

public SubjectInvocationHandler(Object delegate) {
this.delegate = delegate;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long stime = System.currentTimeMillis();
//利用反射机制将请求分派给委托类处理
method.invoke(delegate, args);
long ftime = System.currentTimeMillis();
System.out.println("执行任务耗时"+(ftime - stime)+"毫秒");

return null;
}
}


c.实例演示

Public class DynProxyFactory{
public static Subject getInstance(){
Subject delegate() = new RealSubject();
//这里的handler必须实现invoke方法,并把对委托对象的加强行为写在invoke方法中。
InvocationHandler handler = new SubjectInvocationHandler(delegate);
//直接调用java.lang.Proxy的静态方法,传入handler和委托类的相关信息。剩下的事情交给java自己处理,就能返回一个动态代理对象这个动态代理对象。具体怎么处理,可以深入学习源码
Subject proxy = (Subject)Proxy.newProxyInstance(delegate.getClass().getClassLoader(),delegate.getClass().getInterfaces(),handler);
Return proxy;
}
}


d.至此,客户端可以拿到一个Subject类型的对象,而在调用Subject中的实际方法时,动态代理类会根据传入的方法名,定位到handler的invoke方法并执行,完成代理任务。至于如何定位到handler,也需要深入学习源码。动态代理类,在编译期不存在,在运行期动态生成。其类名为$Proxy+数字。其源码如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
//实现了和委托类一样的Subject接口
public final class $Proxy0 extends Proxy implements Subject{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;

static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
//m3处记录了需要代理的委托方法,方法名为deal
m3 = Class.forName("Subject").getMethod("deal",
new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}

public $Proxy0(InvocationHandler invocationhandler) {

b159
super(invocationhandler);
}
@Override
public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))
.booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
//注意这里的代理方法是final的了
public final void deal() {
try {
//super即proxy类,proxy中的handler属性名是h,至此,最终调用到了invoke方法实现动态代理
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息