所謂代理模式是指:爲其他對象提供一種代理以控制對這個對象的訪問。可以簡單的理解爲,一個類要做某個事,這個類可以把做這個事的權限交予其他類,其他類就成爲了這個類的代理者。比如總經理可以安排自己的日程,也可以把這個任務委託給祕書來做,那麼這麼做的意義是什麼呢?就是祕書做這件事的時候可以做一些總經理不會做的準備性的工作。
第一個例子是一個簡單的代理模式的實現:
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方法的目的。