天天看點

Spring AOP源碼分析(四)Spring AOP的JDK動态代理

本篇文章将會介紹上一個例子中的源碼執行情況,從中熟悉整個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>&lt;aop:config&gt; </code>

<code>        </code><code>&lt;aop:aspect id=</code><code>"testaspect"</code> <code>ref=</code><code>"aspectbean"</code><code>&gt; </code>

<code>            </code> 

<code>            </code><code>&lt;!-- 配置com.spring.service包下所有類或接口的所有方法   --&gt;</code>

<code>            </code><code>&lt;aop:pointcut id=</code><code>"businessservice"</code> 

<code>                </code><code>expression=</code><code>"execution(* com.lg.aop.service.*.*(..))"</code> <code>/&gt; </code>

<code>            </code><code>&lt;aop:before pointcut-ref=</code><code>"businessservice"</code> <code>method=</code><code>"dobefore"</code><code>/&gt; </code>

<code>            </code><code>&lt;aop:after pointcut-ref=</code><code>"businessservice"</code> <code>method=</code><code>"doafter"</code><code>/&gt; </code>

<code>            </code><code>&lt;aop:around pointcut-ref=</code><code>"businessservice"</code> <code>method=</code><code>"doaround"</code><code>/&gt;</code>

<code>            </code><code>&lt;aop:after-throwing pointcut-ref=</code><code>"businessservice"</code> <code>method=</code><code>"dothrowing"</code> <code>throwing=</code><code>"ex"</code><code>/&gt; </code>

<code>        </code><code>&lt;/aop:aspect&gt; </code>

<code>    </code><code>&lt;/aop:config&gt;</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&lt;?&gt;[] 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&lt;advisor&gt; advisors和list&lt;class&lt;?&gt;&gt; interfaces。 

targetsource是目标類型和目标對象的包裹,在這裡是aserviceimpl類和aserviceimpl對象。 

list&lt;class&lt;?&gt;&gt; interfaces:包含了目标類型實作的接口,在這裡就是aservice 

list&lt;advisor&gt; 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&lt;advisor&gt; advisors和list&lt;class&lt;?&gt;&gt; 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>&lt;aop:config expose-proxy=</code><code>"false"</code> <code>proxy-target-</code><code>class</code><code>=</code><code>"false"</code><code>&gt;</code>

<code>&lt;/aop:config&gt;</code>

繼續回到advisedsupport ,對于它的list&lt;advisor&gt; advisors則分别對應xml中的配置: 

<code>&lt;aop:before pointcut-ref=</code><code>"businessservice1"</code> <code>method=</code><code>"dobefore"</code> <code>/&gt; </code>

<code>&lt;aop:after pointcut-ref=</code><code>"businessservice2"</code> <code>method=</code><code>"doafter"</code><code>/&gt; </code>

<code>&lt;aop:around pointcut-ref=</code><code>"businessservice2"</code> <code>method=</code><code>"doaround"</code><code>/&gt;</code>

<code>&lt;aop:after-throwing pointcut-ref=</code><code>"businessservice1"</code> <code>method=</code><code>"dothrowing"</code> <code>throwing=</code><code>"ex"</code><code>/&gt;</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&lt;?&gt; 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 &amp;&amp; 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 &amp;&amp; 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 &amp;&amp; method.getdeclaringclass().isinterface() &amp;&amp;</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&lt;object&gt; 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&lt;?&gt; returntype = method.getreturntype();</code>

<code>            </code><code>if</code> <code>(retval !=</code><code>null</code> <code>&amp;&amp; retval == target &amp;&amp; returntype.isinstance(proxy) &amp;&amp;</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>&amp;&amp; returntype != void.type &amp;&amp; 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>&amp;&amp; !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&lt;object&gt; currentproxy =</code><code>new</code> <code>namedthreadlocal&lt;object&gt;(</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&lt;object&gt; currentproxy,它的兩個方法都是靜态方法,任何線程都可以調用這兩個方法,當線程一調用setcurrentproxy方法時,aopcontext的currentproxy就會去操作線程一内部的資料,當線程二調用setcurrentproxy方法時,aopcontext的currentproxy就會去操作線程二内部的資料,互不幹擾。這種情況不會引起多線程争搶資源資料的情況,同時實作了在某個線程中實作的資料的共享,而不用在某個線程中來回的傳遞參數。這就是threadlocal的設計模式,對于threadlocal&lt;object&gt; currentproxy這樣的類型屬性,它僅僅是操作調用currentproxy的方法的目前線程的工具類,僅此而已。 

繼續,這樣的話就可以實作了在本線程中共享proxy代理對象,這就意味着我們在我們自定義的advice上通過aopcontext可以擷取到目前的代理對象。 

關注的重點2:根據我們的目标類和方法找到對應的攔截器鍊 

list&lt;object&gt; chain = this.advised.getinterceptorsanddynamicinterceptionadvice(method, targetclass); 

它内部是通過advised的一個this.advisorchainfactory來實作這一過程,advisorchainfactory預設為defaultadvisorchainfactory,實作過程如下: 

<code>public</code> <code>list&lt;object&gt; getinterceptorsanddynamicinterceptionadvice(</code>

<code>            </code><code>advised config, method method, class&lt;?&gt; 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&lt;object&gt; interceptorlist =</code><code>new</code> <code>arraylist&lt;object&gt;(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&lt;methodinterceptor&gt; interceptors =</code><code>new</code> <code>arraylist&lt;methodinterceptor&gt;(</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&lt;object&gt; chain = this.advised.getinterceptorsanddynamicinterceptionadvice(method, targetclass);即list&lt;object&gt;是一系列的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&lt;?&gt; targetclass;</code>

<code>        </code><code>protected</code> <code>final</code> <code>list&lt;?&gt; 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&lt;methodinvocation&gt; invocation =</code>

<code>            </code><code>new</code> <code>namedthreadlocal&lt;methodinvocation&gt;(</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配置中指定,下面附上我畫的攔截器鍊的執行流程圖。 

Spring AOP源碼分析(四)Spring AOP的JDK動态代理