所谓代理模式是指:为其他对象提供一种代理以控制对这个对象的访问。可以简单的理解为,一个类要做某个事,这个类可以把做这个事的权限交予其他类,其他类就成为了这个类的代理者。比如总经理可以安排自己的日程,也可以把这个任务委托给秘书来做,那么这么做的意义是什么呢?就是秘书做这件事的时候可以做一些总经理不会做的准备性的工作。
第一个例子是一个简单的代理模式的实现:
Interface:
package com.gc.impl;
public interface TimeBookInterface{
public void doAuditing(String name);
}
Implements:
package com.gc.action;
import com.gc.impl.TimeBookInterface;
public class TimeBook implements TimeBookInterface{
public void doAuditing(String name){
System.out.println("audit now...");
}
}
Proxy:
package com.gc.action;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import com.gc.impl.TimeBookInterface;
public class TimeBookProxy{
private Logger logger = Logger.getLogger(this.getClass().getName());
private TimeBookInterface timeBookInterface;
public TimeBookProxy(TimeBookInterface timeBookInterface){
this.timeBookInterface = timeBookInterface;
}
public void doAuditing(String name){
logger.log(Level.INFO, name+"开始审核数据");
this.timeBookInterface.doAuditing(name);
logger.log(Level.INFO, name+"结束审核数据");
}
}
Test类:
package com.gc.test;
import com.gc.action.*;
public class TestHelloWorld{
public static void main(String[] args) {
TimeBookProxy timeBookProxy = new TimeBookProxy(new TimeBook());
timeBookProxy.doAuditing("张三");
}
}
通过将实现类传入ProxyClass,代理类达到了代理的目的。我们看到代理类调用了指定的方法,并且在调用方法的前后增加了必要的打log逻辑。
这种代理模式不局限于java,同样可以用其他面向对象语言实现。
java同样提供了一种动态代理方式,这种方式基于java的反射的特性,下面提供一个动态代理的例子。接口和类是上例中的类。
LogProxy类:
package com.gc.action;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class logProxy implements InvocationHandler{
private Object delegate;
public Object bind(Object delegate){
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before");
Object result = method.invoke(delegate, args);
System.out.println("after");
return result;
}
}
Test类:
package com.gc.test;
import com.gc.action.*;
import com.gc.impl.*;
public class TestHelloWorld{
public static void main(String[] args){
logProxy logProxy1 = new logProxy();
TimeBookInterface timeBookProxy = (TimeBookInterface)logProxy1.bind(new TimeBook());
timeBookProxy.DoAuditing("张三");
}
}
下面分析一下整个代理的过程:
TimeBookInterface timeBookProxy = (TimeBookInterface)logProxy1.bind(new TimeBook());
public Object bind(Object delegate){
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
}
ProxyClass的bind操作接受一个实现类作为自己的参数,并返回一个代理类,程序将代理类强制转化为TimeBookInterface类型,然后调用TimeBookInterface的相应方法。 先看下运行结果:
最后调用
timeBookProxy.DoAuditing("张三");
方法之后,程序不仅调用了实现类中的doAuditing方法,而且执行了代理类中的两次打印操作,说明最后执行了Proxy类的invoke方法。
那么为什么通过TimeBookInterface调用doAuditing方法可以会调用invoke方法呢?笔者在刚接触这个特性的时候有两个想法:
1、Proxy.newProxyInstance方法调用返回的肯定是一个代理类,并且实现了TimeBookInterface的接口。否则不能强制转化为TimeBookInterface类型。
2、这个代理类还要继承自logProxy类,否则它不能调用invoke方法。
事实这个类是什么样子呢?我们在main方法最前面加上,将生成的ProxyClass打印出来
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
通过JavaDecompiler这个工具得到这个类:
import com.gc.impl.TimeBookInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy
implements TimeBookInterface
{
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void DoAuditing(String paramString)
throws
{
try
{
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.gc.impl.TimeBookInterface").getMethod("DoAuditing", new Class[] { Class.forName("java.lang.String") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
可以看到,当调用这个类的doAuditing方法的时候调用的是 this.h.invoke(this, m3, new Object[] { paramString })
这个类本身继承自Proxy类,查看Proxy源码可知h是invocationHandler,也就是说这个类通过调用传入的invocationHandler的invoke方法而实现代理类中相应方法的调用。在这个例子中,由于logProxy方法实现了invocationHandler,并且把这个参数传给了生成的代理类,这个代理类调用doAuditing方法也就是调用了logProxy方法中的invoke方法,从而达到的代理的效果。
也就是说,第二个猜想是错误的。生成的代理类并没有继承logProxy而是继承自Proxy类,而Proxy类中包含invocationHandler属性,在newProxyInstance的时候,invocationHandler已经传入要生成的代理类,通过调用这个invocationHandler的invoke方法,达到调用logProxy中的invoke方法的目的。