Spring 框架的設計理念與設計模式分析--- Spring中AOP 特性詳解
要了解 Spring 的 AOP 就必須先了解的動態代理的原理,因爲 AOP 就是基於動態代理實現的。動態代理還要從 JDK 本身說起。
在 Jdk 的 java.lang.reflect 包下有個 Proxy 類,它正是構造代理類的入口。這個類的結構入下:
圖 16. Proxy
類結構
從上圖發現最後面四個是公有方法。而最後一個方法 newProxyInstance 就是創建代理對象的方法。這個方法的源碼如下:
清單 6. Proxy. newProxyInstance
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException { if (h == null) { throw new NullPointerException(); } Class cl = getProxyClass(loader, interfaces); 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()); } } |
這個方法需要三個參數:ClassLoader,用於加載代理類的 Loader 類,通常這個 Loader 和被代理的類是同一個 Loader 類。Interfaces,是要被代理的那些那些接口。InvocationHandler,就是用於執行除了被代理接口中方法之外的用戶自定義的操作,他也是用戶需要代理的最終目的。用戶調用目標方法都被代理到 InvocationHandler 類中定義的唯一方法 invoke 中。這在後面再詳解。
下面還是看看 Proxy 如何產生代理類的過程,他構造出來的代理類到底是什麼樣子?下面揭曉啦。
圖 17.
創建代理對象時序圖
其實從上圖中可以發現正在構造代理類的是在 ProxyGenerator 的 generateProxyClass 的方法中。ProxyGenerator 類在 sun.misc 包下,感興趣的話可以看看他的源碼。
假如有這樣一個接口,如下:
清單 7. SimpleProxy
類
public interface SimpleProxy { public void simpleMethod1(); public void simpleMethod2(); } |
代理來生成的類結構如下:
清單 8. $Proxy2
類
public class $Proxy2 extends java.lang.reflect.Proxy implements SimpleProxy{ java.lang.reflect.Method m0; java.lang.reflect.Method m1; java.lang.reflect.Method m2; java.lang.reflect.Method m3; java.lang.reflect.Method m4; int hashCode(); boolean equals(java.lang.Object); java.lang.String toString(); void simpleMethod1(); void simpleMethod2(); } |
這個類中的方法裏面將會是調用 InvocationHandler 的 invoke 方法,而每個方法也將對應一個屬性變量,這個屬性變量 m 也將傳給 invoke 方法中的 Method 參數。整個代理就是這樣實現的。
Spring AOP 如何實現
從前面代理的原理我們知道,代理的目的是調用目標方法時我們可以轉而執行 InvocationHandler 類的 invoke 方法,所以如何在 InvocationHandler 上做文章就是 Spring 實現 Aop 的關鍵所在。
Spring 的 Aop 實現是遵守 Aop 聯盟的約定。同時 Spring 又擴展了它,增加了如 Pointcut、Advisor 等一些接口使得更加靈活。
下面是 Jdk 動態代理的類圖:
圖 18. Jdk
動態代理的類圖
上圖清楚的顯示了 Spring 引用了 Aop Alliance 定義的接口。姑且不討論 Spring 如何擴展 Aop Alliance,先看看 Spring 如何實現代理類的,要實現代理類在 Spring 的配置文件中通常是這樣定一個 Bean 的,如下:
清單 9.
配置代理類 Bean
<bean id="testBeanSingleton" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value> org.springframework.aop.framework.PrototypeTargetTests$TestBean </value> </property> <property name="target"><ref local="testBeanTarget"></ref> </property> <property name="singleton"><value>true</value></property> <property name="interceptorNames"> <list> <value>testInterceptor</value> <value>testInterceptor2</value> </list> </property> </bean> |
配置上看到要設置被代理的接口,和接口的實現類也就是目標類,以及攔截器也就在執行目標方法之前被調用,這裏 Spring 中定義的各種各樣的攔截器,可以選擇使用。
下面看看 Spring 如何完成了代理以及是如何調用攔截器的。
前面提到 Spring Aop 也是實現其自身的擴展點來完成這個特性的,從這個代理類可以看出它正是繼承了 FactoryBean 的 ProxyFactoryBean,FactoryBean 之所以特別就在它可以讓你自定義對象的創建方法。當然代理對象要通過 Proxy 類來動態生成。
下面是 Spring 創建的代理對象的時序圖:
圖 19.Spring
代理對象的產生
Spring 創建了代理對象後,當你調用目標對象上的方法時,將都會被代理到 InvocationHandler 類的 invoke 方法中執行,這在前面已經解釋。在這裏 JdkDynamicAopProxy 類實現了 InvocationHandler 接口。
下面再看看 Spring 是如何調用攔截器的,下面是這個過程的時序圖:
圖 20.Spring
調用攔截器
以上所說的都是 Jdk 動態代理,Spring 還支持一種 CGLIB 類代理,感興趣自己看吧