天天看點

Spring AOP源碼分析(六)Spring AOP配置的背後

本篇文章主要對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>&lt;bean id=</code><code>"aspectbean"</code> <code>class</code><code>=</code><code>"com.lg.aop.testaspect"</code> <code>/&gt;</code>

<code>    </code> 

<code>    </code><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>        </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;aop:pointcut id=</code><code>"businessservice1"</code> 

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

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

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

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

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

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

<code>            </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>

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

<code>    </code><code>&lt;/aop:config&gt;</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中的配置&lt;aop:config&gt;标簽的解析來入手。同樣是從标簽解析接口開始,即找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&lt;element&gt; 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&lt;?&gt; 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的整個運作機制。 

Spring AOP源碼分析(六)Spring AOP配置的背後

然後我們就詳細的說明下整個過程: 

重點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&lt;object&gt; allinterceptors =</code><code>new</code> <code>arraylist&lt;object&gt;();</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 &lt; 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&lt;?&gt; 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&lt;?&gt;[] interfaces = config.getproxiedinterfaces();</code>

<code>        </code><code>return</code> <code>(interfaces.length ==</code><code>0</code> <code>|| (interfaces.length ==</code><code>1</code> <code>&amp;&amp; springproxy.</code><code>class</code><code>.equals(interfaces[</code><code>0</code><code>])));</code>

隻要上述三個條件有一個為true并且目标類不是接口就會采用cglib方式來建立代理對象,其他情況使用jdk動态代理的方式來建立。