本篇文章主要對spring aop配置背後進行了哪些事情做下說明。還是如上類似的工程,在xml中aop攔截配置如下:
<a href="http://my.oschina.net/pingpangkuangmo/blog/376307#">?</a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<code><bean id=</code><code>"aspectbean"</code> <code>class</code><code>=</code><code>"com.lg.aop.testaspect"</code> <code>/></code>
<code> </code>
<code> </code><code><aop:config expose-proxy=</code><code>"false"</code> <code>proxy-target-</code><code>class</code><code>=</code><code>"false"</code><code>> </code>
<code> </code><code><aop:aspect id=</code><code>"testaspect"</code> <code>ref=</code><code>"aspectbean"</code><code>> </code>
<code> </code>
<code> </code><code><aop:pointcut id=</code><code>"businessservice1"</code>
<code> </code><code>expression=</code><code>"execution(* com.lg.aop.service.*.bar*(..))"</code> <code>/> </code>
<code> </code><code><aop:pointcut id=</code><code>"businessservice2"</code>
<code> </code><code>expression=</code><code>"execution(* com.lg.aop.service.*.foo*(..))"</code> <code>/> </code>
<code> </code><code><aop:before pointcut-ref=</code><code>"businessservice1"</code> <code>method=</code><code>"dobefore"</code> <code>/> </code>
<code> </code><code><aop:after pointcut-ref=</code><code>"businessservice2"</code> <code>method=</code><code>"doafter"</code><code>/> </code>
<code> </code><code><aop:around pointcut-ref=</code><code>"businessservice2"</code> <code>method=</code><code>"doaround"</code><code>/></code>
<code> </code><code><aop:after-throwing pointcut-ref=</code><code>"businessservice1"</code> <code>method=</code><code>"dothrowing"</code> <code>throwing=</code><code>"ex"</code><code>/> </code>
<code> </code><code></aop:aspect> </code>
<code> </code><code></aop:config></code>
其中接口aservice和類bserviceimpl都在com.lg.aop.service包下,aservice的實作類
aserviceimpl在com.lg.aop.service.impl包下。
<code>public</code> <code>interface</code> <code>aservice {</code>
<code> </code><code>public</code> <code>void</code> <code>fooa(string _msg); </code>
<code> </code>
<code> </code><code>public</code> <code>void</code> <code>bara();</code>
<code>}</code>
<code>@service</code>
<code>public</code> <code>class</code> <code>bserviceimpl {</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>void</code> <code>barb(string _msg,</code><code>int</code> <code>_type) { </code>
<code> </code><code>system.out.println(</code><code>"bserviceimpl.barb(msg:"</code><code>+_msg+</code><code>" type:"</code><code>+_type+</code><code>")"</code><code>); </code>
<code> </code><code>if</code><code>(_type ==</code><code>1</code><code>) </code>
<code> </code><code>throw</code> <code>new</code> <code>illegalargumentexception(</code><code>"測試異常"</code><code>); </code>
<code> </code><code>} </code>
<code> </code>
<code> </code><code>public</code> <code>void</code> <code>foob() { </code>
<code> </code><code>system.out.println(</code><code>"bserviceimpl.foob()"</code><code>); </code>
<code> </code><code>} </code>
<code>public</code> <code>class</code> <code>aserviceimpl</code><code>implements</code> <code>aservice{</code>
<code> </code><code>@override</code>
<code> </code><code>public</code> <code>void</code> <code>fooa(string _msg) {</code>
<code> </code><code>system.out.println(</code><code>"aserviceimpl.fooa(msg:"</code><code>+_msg+</code><code>")"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>public</code> <code>void</code> <code>bara() {</code>
<code> </code><code>system.out.println(</code><code>"aserviceimpl.bara()"</code><code>); </code>
測試方法如下:
<code>@test</code>
<code> </code><code>public</code> <code>void</code> <code>testaop(){</code>
<code> </code><code>aservice.bara();</code>
<code> </code><code>bserviceimpl.foob();</code>
運作效果如下:
<code>log begining method: com.lg.aop.service.impl.aserviceimpl.bara</code>
<code>aserviceimpl.bara()</code>
<code>bserviceimpl.foob()</code>
<code>process time:</code><code>12</code> <code>ms</code>
<code>log ending method: com.lg.aop.service.bserviceimpl.foob</code>
接下來就需要看下配置完成之後是如何生成代理對象的。
還是要從對xml中的配置<aop:config>标簽的解析來入手。同樣是從标簽解析接口開始,即找beandefinitionparser的實作類,最終我們會找到aspectjautoproxybeandefinitionparser是用來處理aspectj-autoproxy标簽的,而configbeandefinitionparser則是用來處理aop:config标簽的。看下configbeandefinitionparser的解析過程:
16
17
18
19
20
21
22
23
24
<code>public</code> <code>beandefinition parse(element element, parsercontext parsercontext) {</code>
<code> </code><code>compositecomponentdefinition compositedef =</code>
<code> </code><code>new</code> <code>compositecomponentdefinition(element.gettagname(), parsercontext.extractsource(element));</code>
<code> </code><code>parsercontext.pushcontainingcomponent(compositedef);</code>
<code> </code><code>configureautoproxycreator(parsercontext, element);</code>
<code> </code><code>list<element> childelts = domutils.getchildelements(element);</code>
<code> </code><code>for</code> <code>(element elt: childelts) {</code>
<code> </code><code>string localname = parsercontext.getdelegate().getlocalname(elt);</code>
<code> </code><code>if</code> <code>(pointcut.equals(localname)) {</code>
<code> </code><code>parsepointcut(elt, parsercontext);</code>
<code> </code><code>}</code>
<code> </code><code>else</code> <code>if</code> <code>(advisor.equals(localname)) {</code>
<code> </code><code>parseadvisor(elt, parsercontext);</code>
<code> </code><code>else</code> <code>if</code> <code>(aspect.equals(localname)) {</code>
<code> </code><code>parseaspect(elt, parsercontext);</code>
<code> </code><code>}</code>
<code> </code><code>parsercontext.popandregistercontainingcomponent();</code>
<code> </code><code>return</code> <code>null</code><code>;</code>
這個過程比較費勁,有興趣的可以弄清楚。這裡主要注冊一些advisor,同時注冊了一個aspectjawareadvisorautoproxycreator,并且設定xml中所配置的proxy-target-class和expose-proxy到它的屬性中。aspectjawareadvisorautoproxycreator本身存儲着配置資訊,然後使用這些配置建立出來代理對象,在它的父類abstractautoproxycreator的createproxy方法中:
25
26
27
28
29
30
31
32
33
<code>protected</code> <code>object createproxy(</code>
<code> </code><code>class<?> beanclass, string beanname, object[] specificinterceptors, targetsource targetsource) {</code>
<code> </code><code>proxyfactory proxyfactory =</code><code>new</code> <code>proxyfactory();</code>
<code> </code><code>// copy our properties (proxytargetclass etc) inherited from proxyconfig.</code>
<code>//重點1</code>
<code> </code><code>proxyfactory.copyfrom(</code><code>this</code><code>);</code>
<code>//重點2</code>
<code> </code><code>if</code> <code>(!proxyfactory.isproxytargetclass()) {</code>
<code> </code><code>if</code> <code>(shouldproxytargetclass(beanclass, beanname)) {</code>
<code> </code><code>proxyfactory.setproxytargetclass(</code><code>true</code><code>);</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>evaluateproxyinterfaces(beanclass, proxyfactory);</code>
<code> </code><code>advisor[] advisors = buildadvisors(beanname, specificinterceptors);</code>
<code> </code><code>for</code> <code>(advisor advisor : advisors) {</code>
<code> </code><code>proxyfactory.addadvisor(advisor);</code>
<code> </code><code>proxyfactory.settargetsource(targetsource);</code>
<code> </code><code>customizeproxyfactory(proxyfactory);</code>
<code> </code><code>proxyfactory.setfrozen(</code><code>this</code><code>.freezeproxy);</code>
<code> </code><code>if</code> <code>(advisorsprefiltered()) {</code>
<code> </code><code>proxyfactory.setprefiltered(</code><code>true</code><code>);</code>
<code>//重點3</code>
<code> </code><code>return</code> <code>proxyfactory.getproxy(</code><code>this</code><code>.proxyclassloader);</code>
在該方法中建立出代理對象,待會我們再詳細說這個過程。我們先看下proxyfactory是什麼東西。
把下面的圖了解透了,就掌握了springaop的整個運作機制。
然後我們就詳細的說明下整個過程:
重點1:proxyfactory.copyfrom(this);将proxyconfig資訊複制到proxyfactory 中。proxyfactory、aspectjawareadvisorautoproxycreator都繼承了proxyconfig,proxyconfig擁有代理的一些配置資訊。看下proxyconfig:
<code>public</code> <code>class</code> <code>proxyconfig</code><code>implements</code> <code>serializable {</code>
<code> </code><code>/** use serialversionuid from spring 1.2 for interoperability */</code>
<code> </code><code>private</code> <code>static</code> <code>final</code> <code>long</code> <code>serialversionuid = -8409359707199703185l;</code>
<code> </code><code>private</code> <code>boolean</code> <code>proxytargetclass =</code><code>false</code><code>;</code>
<code> </code><code>private</code> <code>boolean</code> <code>optimize =</code><code>false</code><code>;</code>
<code> </code><code>boolean</code> <code>opaque =</code><code>false</code><code>;</code>
<code> </code><code>boolean</code> <code>exposeproxy =</code><code>false</code><code>;</code>
<code> </code><code>private</code> <code>boolean</code> <code>frozen =</code><code>false</code><code>;</code>
含有兩個我們所關注的proxytargetclass,exposeproxy :
proxytargetclass:是否強制使用cglib來實作代理
重點2:複制完配置資訊後,看下proxytargetclass 屬性是否為false,則檢視目标類是否含有接口,若無則仍然設定proxytargetclass為true,若有則把接口設定到proxyfactory中。然後在設定些advisor、targetsource等其他參數,為建立代理對象做準備。來看下上述advisor[] advisors = buildadvisors(beanname, specificinterceptors);的具體内容:
<code>protected</code> <code>advisor[] buildadvisors(string beanname, object[] specificinterceptors) {</code>
<code> </code><code>// handle prototypes correctly...</code>
<code> </code><code>advisor[] commoninterceptors = resolveinterceptornames();</code>
<code> </code><code>list<object> allinterceptors =</code><code>new</code> <code>arraylist<object>();</code>
<code> </code><code>if</code> <code>(specificinterceptors !=</code><code>null</code><code>) {</code>
<code> </code><code>allinterceptors.addall(arrays.aslist(specificinterceptors));</code>
<code> </code><code>if</code> <code>(commoninterceptors !=</code><code>null</code><code>) {</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.applycommoninterceptorsfirst) {</code>
<code> </code><code>allinterceptors.addall(</code><code>0</code><code>, arrays.aslist(commoninterceptors));</code>
<code> </code><code>}</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>allinterceptors.addall(arrays.aslist(commoninterceptors));</code>
<code> </code><code>if</code> <code>(logger.isdebugenabled()) {</code>
<code> </code><code>int</code> <code>nrofcommoninterceptors = (commoninterceptors !=</code><code>null</code> <code>? commoninterceptors.length :</code><code>0</code><code>);</code>
<code> </code><code>int</code> <code>nrofspecificinterceptors = (specificinterceptors !=</code><code>null</code> <code>? specificinterceptors.length :</code><code>0</code><code>);</code>
<code> </code><code>logger.debug(</code><code>"creating implicit proxy for bean '"</code> <code>+ beanname +</code><code>"' with "</code> <code>+ nrofcommoninterceptors +</code>
<code> </code><code>" common interceptors and "</code> <code>+ nrofspecificinterceptors +</code><code>" specific interceptors"</code><code>);</code>
<code> </code><code>advisor[] advisors =</code><code>new</code> <code>advisor[allinterceptors.size()];</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i =</code><code>0</code><code>; i < allinterceptors.size(); i++) {</code>
<code>//重點重點重點重點重點重點重點</code>
<code> </code><code>advisors[i] =</code><code>this</code><code>.advisoradapterregistry.wrap(allinterceptors.get(i));</code>
<code> </code><code>return</code> <code>advisors;</code>
對配置資訊中的specificinterceptors全部封裝成advisor。再看下具體的封裝過程,在上述wrap方法中
<code>public</code> <code>advisor wrap(object adviceobject)</code><code>throws</code> <code>unknownadvicetypeexception {</code>
<code> </code><code>if</code> <code>(adviceobject</code><code>instanceof</code> <code>advisor) {</code>
<code> </code><code>return</code> <code>(advisor) adviceobject;</code>
<code> </code><code>if</code> <code>(!(adviceobject</code><code>instanceof</code> <code>advice)) {</code>
<code> </code><code>throw</code> <code>new</code> <code>unknownadvicetypeexception(adviceobject);</code>
<code> </code><code>advice advice = (advice) adviceobject;</code>
<code> </code><code>if</code> <code>(advice</code><code>instanceof</code> <code>methodinterceptor) {</code>
<code> </code><code>// so well-known it doesn't even need an adapter.</code>
<code> </code><code>return</code> <code>new</code> <code>defaultpointcutadvisor(advice);</code>
<code> </code><code>for</code> <code>(advisoradapter adapter :</code><code>this</code><code>.adapters) {</code>
<code> </code><code>// check that it is supported.</code>
<code> </code><code>if</code> <code>(adapter.supportsadvice(advice)) {</code>
<code> </code><code>return</code> <code>new</code> <code>defaultpointcutadvisor(advice);</code>
<code> </code><code>throw</code> <code>new</code> <code>unknownadvicetypeexception(advice);</code>
重點3:使用defaultaopproxyfactory來建立aopproxy,有了aopproxy我們就能建立代理對象了。看下aopproxy的建立過程:
<code>@override</code>
<code> </code><code>public</code> <code>aopproxy createaopproxy(advisedsupport config)</code><code>throws</code> <code>aopconfigexception {</code>
<code> </code><code>if</code> <code>(config.isoptimize() || config.isproxytargetclass() || hasnousersuppliedproxyinterfaces(config)) {</code>
<code> </code><code>class<?> targetclass = config.gettargetclass();</code>
<code> </code><code>if</code> <code>(targetclass ==</code><code>null</code><code>) {</code>
<code> </code><code>throw</code> <code>new</code> <code>aopconfigexception(</code><code>"targetsource cannot determine target class: "</code> <code>+</code>
<code> </code><code>"either an interface or a target is required for proxy creation."</code><code>);</code>
<code> </code><code>if</code> <code>(targetclass.isinterface()) {</code>
<code> </code><code>return</code> <code>new</code> <code>jdkdynamicaopproxy(config);</code>
<code> </code><code>return</code> <code>new</code> <code>objenesiscglibaopproxy(config);</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>return</code> <code>new</code> <code>jdkdynamicaopproxy(config);</code>
這裡決定着到底采用jdk動态代理還是cglib方式來建立代理對象。
條件1:config.isoptimize()是否進行優化,預設是false。
條件2:config.isproxytargetclass()就是proxyconfig的proxytargetclass屬性,是否強制使用cglib代理。但它為true也不是肯定就采用cglib,因為下面還有一個判斷條件,即目标類是接口,則使用jdk動态代理的方式。
條件3:hasnousersuppliedproxyinterfaces(config)目标類沒有實作接口,或者有但是是接口類型是springproxy,如下:
<code>private</code> <code>boolean</code> <code>hasnousersuppliedproxyinterfaces(advisedsupport config) {</code>
<code> </code><code>class<?>[] interfaces = config.getproxiedinterfaces();</code>
<code> </code><code>return</code> <code>(interfaces.length ==</code><code>0</code> <code>|| (interfaces.length ==</code><code>1</code> <code>&& springproxy.</code><code>class</code><code>.equals(interfaces[</code><code>0</code><code>])));</code>
隻要上述三個條件有一個為true并且目标類不是接口就會采用cglib方式來建立代理對象,其他情況使用jdk動态代理的方式來建立。