代理模式是給某個對象提供一個代理對象,並由代理對象控制對原始對象的引用。以下圖: java
代理類和委託類有共同的父類,這樣在任何使用原始對象(委託對象)的地方均可用代理對象替代。代理對象負責請求的預處理、過濾,將請求分派給原始對象,執行原始對象執行結束後的後續處理。spring
所謂靜態代理,是指在程序運行前,就已經存在代理類的字節碼文件,代理類和原始類(委託類)的關係在運行前就已肯定。編程
所謂動態代理,是指在程序運行期間,由JVM根據反射機制動態生成代理類的字節碼文件,代理類和原始類(委託類)的關係是在運行時肯定的。ide
編寫代理模式,便可實現靜態代理。但這樣的話,有多少個委託類,就須要編寫多少個代理類,即便代理邏輯是相同的。而以AspectJ爲代理的靜態代理,以及JDK動態代理、CGLib動態代理均可以解決這個問題,使得僅需在一個地方編寫代理邏輯,這也是AOP思想和目的。工具
AspectJ是Java語言的一個AOP實現,主要包括兩個部分:第一個部分定義瞭如何表達、定義AOP編程中的語法規範,經過這套語言規範,咱們能夠方便地用 AOP 來解決Java語言中存在的交叉關注點問題;另外一個部分是工具部分,包括編譯器、調試工具等。this
Aspectj實現了獨有的編譯器,在編譯時生成代理類文件。有關AspectJ的用法,參考http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/。代理
Spring AOP的核心就是動態代理。Spring動態代理有兩種實現方式:JDK動態代理和CGLib動態代理,Spring會根據實際狀況自行選擇採用哪一種方式。調試
JDK的動態代理,是基於接口的動態代理。Java API提供以下兩個類幫助咱們實現動態代理:code
如下是java動態代理編寫示例:對象
/** * 主題接口 */ public interface Subject { public void hello(); }
/** * 委託類或原始類 */ public class DelegateSubject implements Subject { public void hello(){ System.out.println("Hello, Word!"); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 調用處理器,負責實現代理邏輯、轉發請求給委託對象 */ public class SubjectInvocationHandler implements InvocationHandler { //代理類持有一個委託類的對象引用 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(); System.out.println(">>begin: "+stime); //利用反射機制將請求轉發給委託類處理,method.invoke返回Object對象做爲方法執行結果。 //由於委託類的相應方法程序沒有返回值,因此這裏不處理返回值 method.invoke(delegate, args); long etime = System.currentTimeMillis(); System.out.println(">>end: "+etime); System.out.println("執行任務耗時" + (etime - stime) + "毫秒。"); return null; } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; /** * 生成代理對象的工廠類 */ public class DynProxyFactory { // 客戶端調用此工廠方法得到代理對象,它並不知道返回的是代理類對象仍是委託類對象。 public static Subject getInstance() { Subject delegate = new DelegateSubject(); InvocationHandler handler = new SubjectInvocationHandler(delegate); Subject proxy = (Subject) Proxy.newProxyInstance( delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), handler); return proxy; } }
/** * 客戶端 */ public class Client { public static void main(String[] args) { Subject proxy = DynProxyFactory.getInstance(); proxy.hello(); } }
儘管java API能夠幫助咱們方便的實現動態代理,但因爲生成的代理類已經繼承了共同的父類(java.lang.reflect.Proxy),這就使得代理類沒法再繼承其它類,而只能實現接口。也就是說,JDK的動態代理機制只能代理實現了接口的類,而沒有實現接口的類就不能代理。
若是要實現對類的動態代理,那就要用CGLib,它的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。
雖然Spring AOP採用了JDK動態代理和CGLib動態代理,但Spring 容許用AspectJ Annotation來定義方面(Aspect)、切入點(Pointcut)和加強處理(Advice), 而不須要使用AspectJ的編譯器和織入器。