本篇文章将會介紹上一個例子中的源碼執行情況,從中熟悉整個springaop的一些概念和接口設計。
首先整個springaop的分兩大過程。
第一個過程:根據xml檔案或者注解中配置的攔截資訊,生成相應的代理對象,這個代理對象包含了對應的攔截器。
第二個過程:執行所攔截的方法時,就是調用代理對象的執行邏輯,完成各種攔截。
本文章先對第二個過程進行源碼解析。
對第一個過程先做簡單概述,如果攔截的類的對應方法是接口方法,則使用jdk的proxy進行代理對象的建立否則使用cglib進行代理對象的建立。
簡單概述如下:
攔截類:testaspect
<a href="http://my.oschina.net/pingpangkuangmo/blog/376305#">?</a>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<code>public</code> <code>void</code> <code>doafter(joinpoint jp) { </code>
<code> </code><code>system.out.println(</code><code>"log ending method: "</code>
<code> </code><code>+ jp.gettarget().getclass().getname() +</code><code>"."</code>
<code> </code><code>+ jp.getsignature().getname()); </code>
<code> </code><code>} </code>
<code> </code>
<code> </code><code>public</code> <code>object doaround(proceedingjoinpoint pjp)</code><code>throws</code> <code>throwable { </code>
<code> </code><code>long</code> <code>time = system.currenttimemillis(); </code>
<code> </code><code>object retval = pjp.proceed(); </code>
<code> </code><code>time = system.currenttimemillis() - time; </code>
<code> </code><code>system.out.println(</code><code>"process time: "</code> <code>+ time +</code><code>" ms"</code><code>); </code>
<code> </code><code>return</code> <code>retval; </code>
<code> </code><code>public</code> <code>void</code> <code>dobefore(joinpoint jp) { </code>
<code> </code><code>system.out.println(</code><code>"log begining method: "</code>
<code> </code><code>public</code> <code>void</code> <code>dothrowing(joinpoint jp, throwable ex) { </code>
<code> </code><code>system.out.println(</code><code>"method "</code> <code>+ jp.gettarget().getclass().getname() </code>
<code> </code><code>+</code><code>"."</code> <code>+ jp.getsignature().getname() +</code><code>" throw exception"</code><code>); </code>
<code> </code><code>system.out.println(ex.getmessage()); </code>
<code> </code><code>}</code>
xml的配置:
<code><aop:config> </code>
<code> </code><code><aop:aspect id=</code><code>"testaspect"</code> <code>ref=</code><code>"aspectbean"</code><code>> </code>
<code> </code>
<code> </code><code><!-- 配置com.spring.service包下所有類或接口的所有方法 --></code>
<code> </code><code><aop:pointcut id=</code><code>"businessservice"</code>
<code> </code><code>expression=</code><code>"execution(* com.lg.aop.service.*.*(..))"</code> <code>/> </code>
<code> </code><code><aop:before pointcut-ref=</code><code>"businessservice"</code> <code>method=</code><code>"dobefore"</code><code>/> </code>
<code> </code><code><aop:after pointcut-ref=</code><code>"businessservice"</code> <code>method=</code><code>"doafter"</code><code>/> </code>
<code> </code><code><aop:around pointcut-ref=</code><code>"businessservice"</code> <code>method=</code><code>"doaround"</code><code>/></code>
<code> </code><code><aop:after-throwing pointcut-ref=</code><code>"businessservice"</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>
建立單元測試類:
<code>@runwith</code><code>(springjunit4classrunner.</code><code>class</code><code>)</code>
<code>@contextconfiguration</code><code>(locations =</code><code>"file:src/main/webapp/web-inf/mvc-servlet.xml"</code><code>)</code>
<code>public</code> <code>class</code> <code>aoptest {</code>
<code> </code><code>@autowired</code>
<code> </code><code>private</code> <code>aservice aservice;</code>
<code> </code><code>private</code> <code>bserviceimpl bserviceimpl;</code>
<code> </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>}</code>
運作,效果如下:
<code>log begining method: com.lg.aop.service.impl.aserviceimpl.bara</code>
<code>aserviceimpl.bara()</code>
<code>process time:</code><code>0</code> <code>ms</code>
<code>log ending method: com.lg.aop.service.impl.aserviceimpl.bara</code>
<code>log begining method: com.lg.aop.service.bserviceimpl.foob</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>
接下來就是分析這一過程。
首先我們會看到:此時的aservice不再是它的實作者aserviceimpl,而是一個代理對象。
由于bara()是接口方法,是以會選擇使用jdk的proxy進行代理對象的建立。如下在jdkdynamicaopproxy中:
<code>@override</code>
<code> </code><code>public</code> <code>object getproxy(classloader classloader) {</code>
<code> </code><code>if</code> <code>(logger.isdebugenabled()) {</code>
<code> </code><code>logger.debug(</code><code>"creating jdk dynamic proxy: target source is "</code> <code>+</code><code>this</code><code>.advised.gettargetsource());</code>
<code> </code><code>}</code>
<code> </code><code>class<?>[] proxiedinterfaces = aopproxyutils.completeproxiedinterfaces(</code><code>this</code><code>.advised);</code>
<code> </code><code>finddefinedequalsandhashcodemethods(proxiedinterfaces);</code>
<code> </code><code>return</code> <code>proxy.newproxyinstance(classloader, proxiedinterfaces,</code><code>this</code><code>);</code>
<code>public</code> <code>object invoke(object proxy, method method, object[] args)</code>
<code> </code><code>throws</code> <code>throwable;</code>
一個代理對象和一個invocationhandler綁定,當執行代理對象的方法時,就會去執行invocationhandler的invoke(object proxy, method method, object[] args)方法,在該方法中你可以選擇相應的處理或者不執行代理對象的method方法。
jdkdynamicaopproxy繼承了invocationhandler,是以上文中在建立代理對象時傳的參數是this,即這個代理對象的方法的執行攔截情況全部在jdkdynamicaopproxy的invoke(object proxy, method method, object[] args)方法中。
我們先來了解下jdkdynamicaopproxy的一些屬性:
<code>final</code> <code>class</code> <code>jdkdynamicaopproxy</code><code>implements</code> <code>aopproxy, invocationhandler, serializable {</code>
<code> </code><code>/** config used to configure this proxy */</code>
<code> </code><code>private</code> <code>final</code> <code>advisedsupport advised;</code>
<code> </code><code>private</code> <code>boolean</code> <code>equalsdefined;</code>
<code> </code><code>private</code> <code>boolean</code> <code>hashcodedefined;</code>
<code> </code><code>//略</code>
最關鍵的就是這個advisedsupport advised屬性,它包含了我們在xml中配置的攔截資訊,同時還包含了這個jdkdynamicaopproxy要代理的接口及其實作類,對于本文來說就是aservice和aserviceimpl。jdkdynamicaopproxy可以根據這些配置資訊來建立一個代理對象實作攔截,同時又可以執行aserviceimpl本身的業務方法。
advisedsupport有兩個重要的内容:targetsource和list<advisor> advisors和list<class<?>> interfaces。
targetsource是目标類型和目标對象的包裹,在這裡是aserviceimpl類和aserviceimpl對象。
list<class<?>> interfaces:包含了目标類型實作的接口,在這裡就是aservice
list<advisor> advisors:這裡包含了我們在xml檔案中配置的所有資訊。這一部分是每個advisedsupport所共享的資訊,而前面兩個是每個advisedsupport所獨有的資訊。
在詳細看下advisedsupport:
<code>public</code> <code>class</code> <code>advisedsupport</code><code>extends</code> <code>proxyconfig</code><code>implements</code> <code>advised</code>
接口advised:主要包含targetsource和list<advisor> advisors和list<class<?>> interface
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:表示是否強制使用cglib進行代理對象的建立
exposeproxy :表示是否暴漏代理對象,實作線程内共享,這裡又是使用threadlocal模式。
他們分别對應xml配置中的
<code><aop:config expose-proxy=</code><code>"false"</code> <code>proxy-target-</code><code>class</code><code>=</code><code>"false"</code><code>></code>
<code></aop:config></code>
繼續回到advisedsupport ,對于它的list<advisor> advisors則分别對應xml中的配置:
<code><aop:before pointcut-ref=</code><code>"businessservice1"</code> <code>method=</code><code>"dobefore"</code> <code>/> </code>
<code><aop:after pointcut-ref=</code><code>"businessservice2"</code> <code>method=</code><code>"doafter"</code><code>/> </code>
<code><aop:around pointcut-ref=</code><code>"businessservice2"</code> <code>method=</code><code>"doaround"</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>
則産生的advisor如下:每一個都是aspectjpointcutadvisor對象,該對象所包含的内容如下:
<code>private</code> <code>final</code> <code>abstractaspectjadvice advice;</code>
<code>private</code> <code>final</code> <code>pointcut pointcut;</code>
<code>private</code> <code>integer order;</code>
分别和xml配置中的内容相對應,在xml中你還可以指定order值,用來排序,這個順序關系到這些攔截方法的執行順序,之後我們會詳細分析這個攔截器鍊的執行情況。
如aop:before産生的aspectjpointcutadvisor的abstractaspectjadvice 為aspectjmethodbeforeadvice,pointcut 為composablepointcut。具體的内容已在上文中接口說明中給出了說明。
至此xml中的配置對應到advisedsupport基本上簡單的了解了,這些内容的建立都是為下文方法的攔截做準備。
下面繼續回到jdkdynamicaopproxy,來看看攔截過程,即調用代理對象的方法,然後被攔截到代理對象的invocationhandler的invoke方法,jdkdynamicaopproxy的invoke方法如下:
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<code>public</code> <code>object invoke(object proxy, method method, object[] args)</code><code>throws</code> <code>throwable {</code>
<code> </code><code>methodinvocation invocation;</code>
<code> </code><code>object oldproxy =</code><code>null</code><code>;</code>
<code> </code><code>boolean</code> <code>setproxycontext =</code><code>false</code><code>;</code>
<code> </code><code>targetsource targetsource =</code><code>this</code><code>.advised.targetsource;</code>
<code> </code><code>class<?> targetclass =</code><code>null</code><code>;</code>
<code> </code><code>object target =</code><code>null</code><code>;</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>if</code> <code>(!</code><code>this</code><code>.equalsdefined && aoputils.isequalsmethod(method)) {</code>
<code> </code><code>// the target does not implement the equals(object) method itself.</code>
<code> </code><code>return</code> <code>equals(args[</code><code>0</code><code>]);</code>
<code> </code><code>}</code>
<code> </code><code>if</code> <code>(!</code><code>this</code><code>.hashcodedefined && aoputils.ishashcodemethod(method)) {</code>
<code> </code><code>// the target does not implement the hashcode() method itself.</code>
<code> </code><code>return</code> <code>hashcode();</code>
<code> </code><code>if</code> <code>(!</code><code>this</code><code>.advised.opaque && method.getdeclaringclass().isinterface() &&</code>
<code> </code><code>method.getdeclaringclass().isassignablefrom(advised.</code><code>class</code><code>)) {</code>
<code> </code><code>// service invocations on proxyconfig with the proxy config...</code>
<code> </code><code>return</code> <code>aoputils.invokejoinpointusingreflection(</code><code>this</code><code>.advised, method, args);</code>
<code> </code><code>object retval;</code>
<code>//我們關注的重點1</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.advised.exposeproxy) {</code>
<code> </code><code>// make invocation available if necessary.</code>
<code> </code><code>oldproxy = aopcontext.setcurrentproxy(proxy);</code>
<code> </code><code>setproxycontext =</code><code>true</code><code>;</code>
<code> </code><code>// may be null. get as late as possible to minimize the time we "own" the target,</code>
<code> </code><code>// in case it comes from a pool.</code>
<code> </code><code>target = targetsource.gettarget();</code>
<code> </code><code>if</code> <code>(target !=</code><code>null</code><code>) {</code>
<code> </code><code>targetclass = target.getclass();</code>
<code>//關注的重點2</code>
<code> </code><code>// get the interception chain for this method.</code>
<code> </code><code>list<object> chain =</code><code>this</code><code>.advised.getinterceptorsanddynamicinterceptionadvice(method, targetclass);</code>
<code> </code><code>// check whether we have any advice. if we don't, we can fallback on direct</code>
<code> </code><code>// reflective invocation of the target, and avoid creating a methodinvocation.</code>
<code> </code><code>if</code> <code>(chain.isempty()) {</code>
<code> </code><code>// we can skip creating a methodinvocation: just invoke the target directly</code>
<code> </code><code>// note that the final invoker must be an invokerinterceptor so we know it does</code>
<code> </code><code>// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.</code>
<code>//關注的重點3</code>
<code> </code><code>retval = aoputils.invokejoinpointusingreflection(target, method, args);</code>
<code> </code><code>else</code> <code>{</code>
<code>//關注的重點4</code>
<code> </code><code>// we need to create a method invocation...</code>
<code> </code><code>invocation =</code><code>new</code> <code>reflectivemethodinvocation(proxy, target, method, args, targetclass, chain);</code>
<code> </code><code>// proceed to the joinpoint through the interceptor chain.</code>
<code> </code><code>retval = invocation.proceed();</code>
<code> </code><code>// massage return value if necessary.</code>
<code> </code><code>class<?> returntype = method.getreturntype();</code>
<code> </code><code>if</code> <code>(retval !=</code><code>null</code> <code>&& retval == target && returntype.isinstance(proxy) &&</code>
<code> </code><code>!rawtargetaccess.</code><code>class</code><code>.isassignablefrom(method.getdeclaringclass())) {</code>
<code> </code><code>// special case: it returned "this" and the return type of the method</code>
<code> </code><code>// is type-compatible. note that we can't help if the target sets</code>
<code> </code><code>// a reference to itself in another returned object.</code>
<code> </code><code>retval = proxy;</code>
<code> </code><code>}</code><code>else</code> <code>if</code> <code>(retval ==</code><code>null</code> <code>&& returntype != void.type && returntype.isprimitive()) {</code>
<code> </code><code>throw</code> <code>new</code> <code>aopinvocationexception(</code><code>"null return value from advice does not match primitive return type for: "</code> <code>+ method);</code>
<code> </code><code>return</code> <code>retval;</code>
<code> </code><code>finally</code> <code>{</code>
<code> </code><code>if</code> <code>(target !=</code><code>null</code> <code>&& !targetsource.isstatic()) {</code>
<code> </code><code>// must have come from targetsource.</code>
<code> </code><code>targetsource.releasetarget(target);</code>
<code> </code><code>if</code> <code>(setproxycontext) {</code>
<code> </code><code>// restore old proxy.</code>
<code> </code><code>aopcontext.setcurrentproxy(oldproxy);</code>
<code>private</code> <code>static</code> <code>final</code> <code>threadlocal<object> currentproxy =</code><code>new</code> <code>namedthreadlocal<object>(</code><code>"current aop proxy"</code><code>);</code>
<code>public</code> <code>static</code> <code>object currentproxy()</code><code>throws</code> <code>illegalstateexception {</code>
<code> </code><code>object proxy = currentproxy.get();</code>
<code> </code><code>if</code> <code>(proxy ==</code><code>null</code><code>) {</code>
<code> </code><code>throw</code> <code>new</code> <code>illegalstateexception(</code>
<code> </code><code>"cannot find current proxy: set 'exposeproxy' property on advised to 'true' to make it available."</code><code>);</code>
<code> </code><code>return</code> <code>proxy;</code>
<code>static</code> <code>object setcurrentproxy(object proxy) {</code>
<code> </code><code>object old = currentproxy.get();</code>
<code> </code><code>if</code> <code>(proxy !=</code><code>null</code><code>) {</code>
<code> </code><code>currentproxy.set(proxy);</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>currentproxy.remove();</code>
<code> </code><code>return</code> <code>old;</code>
aopcontext内部使用了一個threadlocal<object> currentproxy,它的兩個方法都是靜态方法,任何線程都可以調用這兩個方法,當線程一調用setcurrentproxy方法時,aopcontext的currentproxy就會去操作線程一内部的資料,當線程二調用setcurrentproxy方法時,aopcontext的currentproxy就會去操作線程二内部的資料,互不幹擾。這種情況不會引起多線程争搶資源資料的情況,同時實作了在某個線程中實作的資料的共享,而不用在某個線程中來回的傳遞參數。這就是threadlocal的設計模式,對于threadlocal<object> currentproxy這樣的類型屬性,它僅僅是操作調用currentproxy的方法的目前線程的工具類,僅此而已。
繼續,這樣的話就可以實作了在本線程中共享proxy代理對象,這就意味着我們在我們自定義的advice上通過aopcontext可以擷取到目前的代理對象。
關注的重點2:根據我們的目标類和方法找到對應的攔截器鍊
list<object> chain = this.advised.getinterceptorsanddynamicinterceptionadvice(method, targetclass);
它内部是通過advised的一個this.advisorchainfactory來實作這一過程,advisorchainfactory預設為defaultadvisorchainfactory,實作過程如下:
<code>public</code> <code>list<object> getinterceptorsanddynamicinterceptionadvice(</code>
<code> </code><code>advised config, method method, class<?> targetclass) {</code>
<code> </code><code>// this is somewhat tricky... we have to process introductions first,</code>
<code> </code><code>// but we need to preserve order in the ultimate list.</code>
<code> </code><code>list<object> interceptorlist =</code><code>new</code> <code>arraylist<object>(config.getadvisors().length);</code>
<code> </code><code>boolean</code> <code>hasintroductions = hasmatchingintroductions(config, targetclass);</code>
<code> </code><code>advisoradapterregistry registry = globaladvisoradapterregistry.getinstance();</code>
<code> </code><code>for</code> <code>(advisor advisor : config.getadvisors()) {</code>
<code> </code><code>if</code> <code>(advisor</code><code>instanceof</code> <code>pointcutadvisor) {</code>
<code> </code><code>// add it conditionally.</code>
<code> </code><code>pointcutadvisor pointcutadvisor = (pointcutadvisor) advisor;</code>
<code> </code><code>if</code> <code>(config.isprefiltered() || pointcutadvisor.getpointcut().getclassfilter().matches(targetclass)) {</code>
<code> </code><code>methodinterceptor[] interceptors = registry.getinterceptors(advisor);</code>
<code> </code><code>methodmatcher mm = pointcutadvisor.getpointcut().getmethodmatcher();</code>
<code> </code><code>if</code> <code>(methodmatchers.matches(mm, method, targetclass, hasintroductions)) {</code>
<code> </code><code>if</code> <code>(mm.isruntime()) {</code>
<code> </code><code>// creating a new object instance in the getinterceptors() method</code>
<code> </code><code>// isn't a problem as we normally cache created chains.</code>
<code> </code><code>for</code> <code>(methodinterceptor interceptor : interceptors) {</code>
<code> </code><code>interceptorlist.add(</code><code>new</code> <code>interceptoranddynamicmethodmatcher(interceptor, mm));</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>interceptorlist.addall(arrays.aslist(interceptors));</code>
<code> </code><code>}</code>
<code> </code><code>}</code>
<code> </code><code>else</code> <code>if</code> <code>(advisor</code><code>instanceof</code> <code>introductionadvisor) {</code>
<code> </code><code>introductionadvisor ia = (introductionadvisor) advisor;</code>
<code> </code><code>if</code> <code>(config.isprefiltered() || ia.getclassfilter().matches(targetclass)) {</code>
<code> </code><code>interceptor[] interceptors = registry.getinterceptors(advisor);</code>
<code> </code><code>interceptorlist.addall(arrays.aslist(interceptors));</code>
<code> </code><code>interceptor[] interceptors = registry.getinterceptors(advisor);</code>
<code> </code><code>interceptorlist.addall(arrays.aslist(interceptors));</code>
<code> </code><code>return</code> <code>interceptorlist;</code>
上述過程分了三種情況來擷取對應的interceptor攔截器,config.getadvisors()是我們在xml檔案中所配置的所有的攔截情況,對于這些所有的攔截情況:
當advisor為pointcutadvisor類型的時:
這是我們本工程的配置的攔截,每個攔截都有pointcut,針對這種情況,首先判斷該pointcutadvisor的classfilter是否攔截了targetclass,若攔截則需繼續判斷pointcutadvisor的methodmatcher是否攔截targetclass的method方法。如果也攔截了,就需要将pointcutadvisor的adice添加進去,則繼續判斷這個pointcutadvisor的methodmatcher是否是動态變化的,若是則需要将interceptor進一步包裝成interceptoranddynamicmethodmatcher然後添加進去。
當advisor為introductionadvisor類型的時候:
introductionadvisor應用在類上,不需要判斷是否攔截了相應的方法。introductionadvisor隻有一個classfilter。此時僅僅去判斷下是否攔截相應的類即可。
其他情況:
直接擷取相應的interceptor。
我們來看下根據advisor來擷取對應的methodinterceptor方法:
<code>public</code> <code>methodinterceptor[] getinterceptors(advisor advisor)</code><code>throws</code> <code>unknownadvicetypeexception {</code>
<code> </code><code>list<methodinterceptor> interceptors =</code><code>new</code> <code>arraylist<methodinterceptor>(</code><code>3</code><code>);</code>
<code> </code><code>advice advice = advisor.getadvice();</code>
<code> </code><code>if</code> <code>(advice</code><code>instanceof</code> <code>methodinterceptor) {</code>
<code> </code><code>interceptors.add((methodinterceptor) advice);</code>
<code> </code><code>for</code> <code>(advisoradapter adapter :</code><code>this</code><code>.adapters) {</code>
<code> </code><code>if</code> <code>(adapter.supportsadvice(advice)) {</code>
<code> </code><code>interceptors.add(adapter.getinterceptor(advisor));</code>
<code> </code><code>if</code> <code>(interceptors.isempty()) {</code>
<code> </code><code>throw</code> <code>new</code> <code>unknownadvicetypeexception(advisor.getadvice());</code>
<code> </code><code>return</code> <code>interceptors.toarray(</code><code>new</code> <code>methodinterceptor[interceptors.size()]);</code>
首先是判斷advisor.getadvice()是否已實作了methodinterceptor,如aspectjafteradvice、aspectjafterthrowingadvice等。
然後又是利用擴充卡模式,将不用的advice封裝成對應的methodinterceptor。如methodbeforeadviceadapter,預設寫死注冊了三個
<code>public</code> <code>defaultadvisoradapterregistry() {</code>
<code> </code><code>registeradvisoradapter(</code><code>new</code> <code>methodbeforeadviceadapter());</code>
<code> </code><code>registeradvisoradapter(</code><code>new</code> <code>afterreturningadviceadapter());</code>
<code> </code><code>registeradvisoradapter(</code><code>new</code> <code>throwsadviceadapter());</code>
看下methodbeforeadviceadapter:
<code>class</code> <code>methodbeforeadviceadapter</code><code>implements</code> <code>advisoradapter, serializable {</code>
<code> </code><code>@override</code>
<code> </code><code>public</code> <code>boolean</code> <code>supportsadvice(advice advice) {</code>
<code> </code><code>return</code> <code>(advice</code><code>instanceof</code> <code>methodbeforeadvice);</code>
<code> </code><code>public</code> <code>methodinterceptor getinterceptor(advisor advisor) {</code>
<code> </code><code>methodbeforeadvice advice = (methodbeforeadvice) advisor.getadvice();</code>
<code> </code><code>return</code> <code>new</code> <code>methodbeforeadviceinterceptor(advice);</code>
這就是典型的擴充卡模式,當advice為methodbeforeadvice時,就會封裝成methodbeforeadviceinterceptor。
至此擷取methodinterceptor鍊的過程就完成了,回到list<object> chain = this.advised.getinterceptorsanddynamicinterceptionadvice(method, targetclass);即list<object>是一系列的methodinterceptor構成的。
繼續看jdkdynamicaopproxy的invoke攔截方法:
關注重點3:在擷取methodinterceptor鍊後,如果為空,則沒有攔截器直接執行目标對象的方法。retval = aoputils.invokejoinpointusingreflection(target, method, args);中的target對于本工程來說就是aserviceimpl,是以此方法的本質就是利用反射執行aserviceimpl的method方法。如下:
<code>public</code> <code>static</code> <code>object invokejoinpointusingreflection(object target, method method, object[] args)</code>
<code> </code><code>throws</code> <code>throwable {</code>
<code> </code><code>// use reflection to invoke the method.</code>
<code> </code><code>reflectionutils.makeaccessible(method);</code>
<code> </code><code>return</code> <code>method.invoke(target, args);</code>
<code> </code><code>//略</code>
關注的重點4: 有了攔截器鍊後,就構造一個reflectivemethodinvocation來完成這一個調用過程。
首先說下接口情況:reflectivemethodinvocation實作了proxymethodinvocation,proxymethodinvocation繼承了methodinvocation,
methodinvocation繼承了invocation,
invocation繼承了joinpoint,此時的joinpoint是aop聯盟定義的接口。
aspectj也有一個類似的joinpoint,這兩個是不一樣的。
joinpoint:能夠得到目标對象,同時指定了對目标對象的處理方法
<code>//定義了一個proceed()方法,來處理這些攔截器鍊的調用過程</code>
<code> </code><code>object proceed()</code><code>throws</code> <code>throwable;</code>
<code>//傳回目标對象,針對本工程就是aserviceimpl</code>
<code> </code><code>object getthis();</code>
invocation:能夠擷取方法參數,此時方法可以是構造方法也可以是一般方法
<code>object[] getarguments();</code>
methodinvocation:能夠擷取方法而不是構造方法,constructorinvocation才是擷取構造方法,是以有了methodinvocation就可以執行目标對象的方法了。
<code>method getmethod();</code>
proxymethodinvocation:能夠擷取代理代理對象,這個在around通知時發揮作用,稍後會看到。
<code>object getproxy();</code>
此時reflectivemethodinvocation就擁有以下資料:
<code>protected</code> <code>final</code> <code>object proxy;</code>
<code> </code><code>protected</code> <code>final</code> <code>object target;</code>
<code> </code><code>protected</code> <code>final</code> <code>method method;</code>
<code> </code><code>protected</code> <code>object[] arguments;</code>
<code> </code><code>private</code> <code>final</code> <code>class<?> targetclass;</code>
<code> </code><code>protected</code> <code>final</code> <code>list<?> interceptorsanddynamicmethodmatchers;</code>
interceptorsanddynamicmethodmatchers則是由重點2中得出的攔截器鍊傳給reflectivemethodinvocation的。然後看下reflectivemethodinvocation作為一個joinpoint的proceed方法的執行過程:
<code>public</code> <code>object proceed()</code><code>throws</code> <code>throwable {</code>
<code> </code><code>// we start with an index of -1 and increment early.</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.currentinterceptorindex ==</code><code>this</code><code>.interceptorsanddynamicmethodmatchers.size() -</code><code>1</code><code>) {</code>
<code> </code><code>return</code> <code>invokejoinpoint();</code>
<code> </code><code>object interceptororinterceptionadvice =</code>
<code> </code><code>this</code><code>.interceptorsanddynamicmethodmatchers.get(++</code><code>this</code><code>.currentinterceptorindex);</code>
<code> </code><code>if</code> <code>(interceptororinterceptionadvice</code><code>instanceof</code> <code>interceptoranddynamicmethodmatcher) {</code>
<code> </code><code>// evaluate dynamic method matcher here: static part will already have</code>
<code> </code><code>// been evaluated and found to match.</code>
<code> </code><code>interceptoranddynamicmethodmatcher dm =</code>
<code> </code><code>(interceptoranddynamicmethodmatcher) interceptororinterceptionadvice;</code>
<code> </code><code>if</code> <code>(dm.methodmatcher.matches(</code><code>this</code><code>.method,</code><code>this</code><code>.targetclass,</code><code>this</code><code>.arguments)) {</code>
<code> </code><code>return</code> <code>dm.interceptor.invoke(</code><code>this</code><code>);</code>
<code> </code><code>// dynamic matching failed.</code>
<code> </code><code>// skip this interceptor and invoke the next in the chain.</code>
<code> </code><code>return</code> <code>proceed();</code>
<code> </code><code>// it's an interceptor, so we just invoke it: the pointcut will have</code>
<code> </code><code>// been evaluated statically before this object was constructed.</code>
<code> </code><code>return</code> <code>((methodinterceptor) interceptororinterceptionadvice).invoke(</code><code>this</code><code>);</code>
首先就是this.currentinterceptorindex,它是reflectivemethodinvocation的一個屬性,從-1開始:
<code>private</code> <code>int</code> <code>currentinterceptorindex = -</code><code>1</code><code>;</code>
當currentinterceptorindex達到this.interceptorsanddynamicmethodmatchers.size() - 1時,攔截器鍊執行完畢了,就去執行目标對象的方法。invokejoinpoint()方法就是上文我們所說的通過反射進行目标方法的調用。
繼續看,拿出一個interceptororinterceptionadvice,判斷它是不是interceptoranddynamicmethodmatcher類型,這個類型在擷取攔截器鍊的時候遇見了,我們再次回顧下:
<code>for</code> <code>(advisor advisor : config.getadvisors()) {</code>
<code>//重點在這裡重點在這裡重點在這裡重點在這裡重點在這裡</code>
<code>//略</code>
因為interceptoranddynamicmethodmatcher的methodmatcher是可變的,是以在執行前仍要進行判斷一次,符合的話就執行interceptoranddynamicmethodmatcher中所包含的methodinterceptor。不符合的話跳過本次攔截器,繼續執行下一個攔截器。
當攔截器是methodinterceptor,則是執行這個攔截器。
然後我們來看下具體有哪些攔截器鍊,以及具體是怎樣的執行過程:
我們會看到會有如下5個攔截器,依次是:
exposeinvocationinterceptor、methodbeforeadviceinterceptor、aspectjafteradvice、aspectjaroundadvice、aspectjafterthrowingadvice。
首先看第一個exposeinvocationinterceptor:
它是spring自動幫我們添加的,它不屬于interceptoranddynamicmethodmatcher類型,即不再進行判斷是否符合目前函數。
看下它的invoke方法的内容:
<code>public</code> <code>object invoke(methodinvocation mi)</code><code>throws</code> <code>throwable {</code>
<code> </code><code>methodinvocation oldinvocation = invocation.get();</code>
<code> </code><code>invocation.set(mi);</code>
<code> </code><code>return</code> <code>mi.proceed();</code>
<code> </code><code>invocation.set(oldinvocation);</code>
其中methodinvocation mi始終是剛建立的reflectivemethodinvocation對象,它包含了一切要執行的資訊。invocation則是一個threadlocal類型,如下:
<code>private</code> <code>static</code> <code>final</code> <code>threadlocal<methodinvocation> invocation =</code>
<code> </code><code>new</code> <code>namedthreadlocal<methodinvocation>(</code><code>"current aop method invocation"</code><code>);</code>
同時exposeinvocationinterceptor的currentinvocation方法用于擷取目前線程的reflectivemethodinvocation對象
<code>public</code> <code>static</code> <code>methodinvocation currentinvocation()</code><code>throws</code> <code>illegalstateexception {</code>
<code> </code><code>methodinvocation mi = invocation.get();</code>
<code> </code><code>if</code> <code>(mi ==</code><code>null</code><code>)</code>
<code> </code><code>"no methodinvocation found: check that an aop invocation is in progress, and that the "</code> <code>+</code>
<code> </code><code>"exposeinvocationinterceptor is upfront in the interceptor chain. specifically, note that "</code> <code>+</code>
<code> </code><code>"advices with order highest_precedence will execute before exposeinvocationinterceptor!"</code><code>);</code>
<code> </code><code>return</code> <code>mi;</code>
exposeinvocationinterceptor即分析完了,此時exposeinvocationinterceptor的invoke函數還沒有執行完畢,然後就嵌套執行reflectivemethodinvocation對象的proceed方法,
擷取下一個攔截器methodbeforeadviceinterceptor,并且判斷類型也屬于interceptoranddynamicmethodmatcher類型的(我們自定義的幾個都不屬于),
和exposeinvocationinterceptor一樣,直接執行,看下methodbeforeadviceinterceptor的invoke函數:
<code> </code><code>this</code><code>.advice.before(mi.getmethod(), mi.getarguments(), mi.getthis() );</code>
<code> </code><code>return</code> <code>mi.proceed();</code>
先會執行我們在xml檔案中配置好的advice,即我們自定義的dobefore方法,這就是前置通知。然後繼續嵌套執行reflectivemethodinvocation對象的proceed方法,輪到了aspectjafteradvice的invoke方法:
<code> </code><code>public</code> <code>object invoke(methodinvocation mi)</code><code>throws</code> <code>throwable {</code>
<code> </code><code>invokeadvicemethod(getjoinpointmatch(),</code><code>null</code><code>,</code><code>null</code><code>);</code>
它的執行順序則是先去執行後面的内容,當都執行完畢了才傳回來執行這個advice。這就是後置通知。繼續嵌套執行reflectivemethodinvocation對象的proceed方法,來到了aspectjaroundadvice的invoke方法:
<code> </code><code>if</code> <code>(!(mi</code><code>instanceof</code> <code>proxymethodinvocation)) {</code>
<code> </code><code>throw</code> <code>new</code> <code>illegalstateexception(</code><code>"methodinvocation is not a spring proxymethodinvocation: "</code> <code>+ mi);</code>
<code> </code><code>proxymethodinvocation pmi = (proxymethodinvocation) mi;</code>
<code> </code><code>proceedingjoinpoint pjp = lazygetproceedingjoinpoint(pmi);</code>
<code> </code><code>joinpointmatch jpm = getjoinpointmatch(pmi);</code>
<code> </code><code>return</code> <code>invokeadvicemethod(pjp, jpm,</code><code>null</code><code>,</code><code>null</code><code>);</code>
<code>protected</code> <code>proceedingjoinpoint lazygetproceedingjoinpoint(proxymethodinvocation rmi) {</code>
<code> </code><code>return</code> <code>new</code> <code>methodinvocationproceedingjoinpoint(rmi);</code>
lazygetproceedingjoinpoint(pmi)就是将reflectivemethodinvocation對象作為一個proxymethodinvocation封裝成一個methodinvocationproceedingjoinpoint,如下:
<code>public</code> <code>methodinvocationproceedingjoinpoint(proxymethodinvocation methodinvocation) {</code>
<code> </code><code>assert.notnull(methodinvocation,</code><code>"methodinvocation must not be null"</code><code>);</code>
<code> </code><code>this</code><code>.methodinvocation = methodinvocation;</code>
這個就是環繞通知,我們看下這通知我們所寫的具體内容:
<code>public</code> <code>object doaround(proceedingjoinpoint pjp)</code><code>throws</code> <code>throwable { </code>
這裡面有一個很重要的資訊proceedingjoinpoint pjp,它決定了reflectivemethodinvocation的執行鍊是否繼續執行下去,是以pjp.proceed()的本質仍然是調用reflectivemethodinvocation的proceed()方法,來繼續下面攔截器的執行,也可以選擇不執行,則攔截器鍊的執行就會終止了,會從不斷嵌套的proceed函數中不斷傳回。
這裡将會執行到我們自定義的上面的doaround方法,當執行到pjp.proceed()時,又會返還到
reflectivemethodinvocation的proceed()執行下一個攔截器,來到aspectjafterthrowingadvice,它的invoke方法為:
<code> </code><code>catch</code> <code>(throwable t) {</code>
<code> </code><code>if</code> <code>(shouldinvokeonthrowing(t)) {</code>
<code> </code><code>invokeadvicemethod(getjoinpointmatch(),</code><code>null</code><code>, t);</code>
<code> </code><code>throw</code> <code>t;</code>
即先執行後面的攔截器,但後面的攔截器執行過程中出現異常時才會發揮該攔截器的作用。繼續執行後面的攔截器,發現已經沒了,則終于輪到目标對象的方法了,目标方法執行完畢後,傳回上一個proceed的嵌套即aspectjafterthrowingadvice的invoke方法,發現沒有抛出異常,則繼續傳回到上一個proceed嵌套,即aspectjaroundadvice,即我們自定義的doaround中這一行代碼object retval = pjp.proceed()傳回了,繼續完成我們自定義的doaround函數,完成後再傳回上一個proceed嵌套,來到aspectjafteradvice,則開始執行這個advice的處理工作,即我們自定義的doafter方法。再傳回上一個proceed嵌套,來到methodbeforeadviceinterceptor,發現已經執行完畢繼續傳回上一個嵌套來到exposeinvocationinterceptor,繼續完成餘下的工作,至此整個攔截過程就分析完畢了。在此過程中一個重要的參數就是我們配置的攔截器的順序,順序不同時執行過程就不一樣,我們可以通過在xml配置中指定,下面附上我畫的攔截器鍊的執行流程圖。