這篇文章裡面就要說說spring自己的aop,搞清楚哪種方式是spring自己實作的aop,哪種方式是spring引入aspectj的aop。
spring自己的aop實作在于proxyfactorybean。先看下使用案例(仍和之前的案例是一樣的):接口aservice、實作類aserviceimpl、通知mybeforeadvice
<a href="http://my.oschina.net/pingpangkuangmo/blog/376308#">?</a>
1
2
3
4
5
6
<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>
7
8
9
10
11
12
13
<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>public</code> <code>class</code> <code>mybeforeadvice</code><code>implements</code> <code>methodbeforeadvice{</code>
<code> </code><code>public</code> <code>void</code> <code>before(method method, object[] args, object target)</code>
<code> </code><code>throws</code> <code>throwable {</code>
<code> </code><code>system.out.println(</code><code>"run my before advice"</code><code>);</code>
然後就是xml的配置:
14
<code><bean id=</code><code>"aserviceimpl"</code> <code>class</code><code>=</code><code>"com.lg.aop.service.impl.aserviceimpl"</code><code>/></code>
<code> </code><code><bean id=</code><code>"mybeforadvice"</code> <code>class</code><code>=</code><code>"com.lg.aop.mybeforeadvice"</code><code>/></code>
<code> </code>
<code> </code><code><bean</code><code>class</code><code>=</code><code>"org.springframework.aop.framework.proxyfactorybean"</code><code>></code>
<code> </code><code><property name=</code><code>"interfaces"</code> <code>value=</code><code>"com.lg.aop.service.aservice"</code><code>/></code>
<code> </code><code><property name=</code><code>"target"</code><code>></code>
<code> </code><code><ref bean=</code><code>"aserviceimpl"</code><code>/></code>
<code> </code><code></property></code>
<code> </code><code><property name=</code><code>"interceptornames"</code><code>> </code>
<code> </code><code><list> </code>
<code> </code><code><value>mybeforadvice</value> </code>
<code> </code><code></list> </code>
<code> </code><code></property> </code>
<code> </code><code></bean></code>
然後就可以使用了:
<code>@autowired</code>
<code> </code><code>private</code> <code>aservice aservice;</code>
<code> </code><code>@test</code>
<code> </code><code>public</code> <code>void</code> <code>testaop(){</code>
<code> </code><code>aservice.bara();</code>
運作這個單元測試,然後你就會看到報如下錯誤:
<code>no qualifying bean of type [com.lg.aop.service.aservice] is defined: expected single matching bean but found</code><code>2</code><code>: aserviceimpl,org.springframework.aop.framework.proxyfactorybean#</code><code>0</code>
原因就是對于接口aservice,有兩個實作類aserviceimpl和proxyfactorybean所生産的代理類。是以我們不能使用@autowired(它是按類型注入),是以要使用按名稱注入,我們怎麼擷取proxyfactorybean所産生的代理類的名稱呢?其實就是proxyfactorybean配置的名稱。因為proxyfactorybean實作了factorybean接口,對于這種接口從容器中擷取該bean,不是擷取的本身而是擷取他的getobject方法所傳回的值,看factorybean的文檔:
<code>/**</code>
<code> </code><code>* interface to be implemented by objects used within a {</code><code>@link</code> <code>beanfactory}</code>
<code> </code><code>* which are themselves factories. if a bean</code><code>implements</code> <code>this</code> <code>interface</code><code>,</code>
<code> </code><code>* it is used as a factory</code><code>for</code> <code>an object to expose, not directly as a bean</code>
<code> </code><code>* instance that will be exposed itself.</code>
<code> </code><code>*</code>
<code> </code><code>* <p><b>nb: a bean that</code><code>implements</code> <code>this</code> <code>interface</code> <code>cannot be used as a</code>
<code> </code><code>* normal bean.</b> a factorybean is defined in a bean style, but the</code>
<code> </code><code>* object exposed</code><code>for</code> <code>bean references ({</code><code>@link</code> <code>#getobject()} is always</code>
<code> </code><code>* the object that it creates.</code>
是以通過beanname找到了proxyfactorybean,然而不是傳回該對象,而是傳回他的getobject方法的傳回值,是以我們通過proxyfactorybean的id就可以擷取到它所産生的代理對象,是以更改如下:
<code><bean id=</code><code>"aserviceimplproxy"</code> <code>class</code><code>=</code><code>"org.springframework.aop.framework.proxyfactorybean"</code><code>></code>
<code>其他略</code>
在使用注入的時候按名稱注入
<code>@resource</code><code>(name=</code><code>"aserviceimplproxy"</code><code>)</code>
然後就可以正常運作了如下:
<code>run my before advice</code>
<code>aserviceimpl.bara()</code>
然後我們就要源碼分析下這一過程,先看下是如何産生代理對象的,在proxyfactorybean的getobject方法中:
15
<code>public</code> <code>object getobject()</code><code>throws</code> <code>beansexception {</code>
<code>//重點1</code>
<code> </code><code>initializeadvisorchain();</code>
<code> </code><code>if</code> <code>(issingleton()) {</code>
<code>//重點2</code>
<code> </code><code>return</code> <code>getsingletoninstance();</code>
<code> </code><code>}</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.targetname ==</code><code>null</code><code>) {</code>
<code> </code><code>logger.warn(</code><code>"using non-singleton proxies with singleton targets is often undesirable. "</code> <code>+</code>
<code> </code><code>"enable prototype proxies by setting the 'targetname' property."</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>return</code> <code>newprototypeinstance();</code>
重點1:就是根據我們配置的interceptornames來擷取對應的bean,并卻轉化成advisor。如下:
16
17
18
19
20
21
22
23
24
25
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
<code>private</code> <code>synchronized</code> <code>void</code> <code>initializeadvisorchain()</code><code>throws</code> <code>aopconfigexception, beansexception {</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.advisorchaininitialized) {</code>
<code> </code><code>return</code><code>;</code>
<code> </code><code>if</code> <code>(!objectutils.isempty(</code><code>this</code><code>.interceptornames)) {</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.beanfactory ==</code><code>null</code><code>) {</code>
<code> </code><code>throw</code> <code>new</code> <code>illegalstateexception(</code><code>"no beanfactory available anymore (probably due to serialization) "</code> <code>+</code>
<code> </code><code>"- cannot resolve interceptor names "</code> <code>+ arrays.aslist(</code><code>this</code><code>.interceptornames));</code>
<code> </code><code>// globals can't be last unless we specified a targetsource using the property...</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.interceptornames[</code><code>this</code><code>.interceptornames.length -</code><code>1</code><code>].endswith(global_suffix) &&</code>
<code> </code><code>this</code><code>.targetname ==</code><code>null</code> <code>&&</code><code>this</code><code>.targetsource == empty_target_source) {</code>
<code> </code><code>throw</code> <code>new</code> <code>aopconfigexception(</code><code>"target required after globals"</code><code>);</code>
<code> </code><code>// materialize interceptor chain from bean names.</code>
<code> </code><code>for</code> <code>(string name :</code><code>this</code><code>.interceptornames) {</code>
<code> </code><code>if</code> <code>(logger.istraceenabled()) {</code>
<code> </code><code>logger.trace(</code><code>"configuring advisor or advice '"</code> <code>+ name +</code><code>"'"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>if</code> <code>(name.endswith(global_suffix)) {</code>
<code> </code><code>if</code> <code>(!(</code><code>this</code><code>.beanfactory</code><code>instanceof</code> <code>listablebeanfactory)) {</code>
<code> </code><code>throw</code> <code>new</code> <code>aopconfigexception(</code>
<code> </code><code>"can only use global advisors or interceptors with a listablebeanfactory"</code><code>);</code>
<code> </code><code>}</code>
<code> </code><code>addglobaladvisor((listablebeanfactory)</code><code>this</code><code>.beanfactory,</code>
<code> </code><code>name.substring(</code><code>0</code><code>, name.length() - global_suffix.length()));</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>// if we get here, we need to add a named interceptor.</code>
<code> </code><code>// we must check if it's a singleton or prototype.</code>
<code> </code><code>object advice;</code>
<code> </code><code>if</code> <code>(</code><code>this</code><code>.singleton ||</code><code>this</code><code>.beanfactory.issingleton(name)) {</code>
<code> </code><code>// add the real advisor/advice to the chain.</code>
<code> </code><code>advice =</code><code>this</code><code>.beanfactory.getbean(name);</code>
<code> </code><code>else</code> <code>{</code>
<code> </code><code>// it's a prototype advice or advisor: replace with a prototype.</code>
<code> </code><code>// avoid unnecessary creation of prototype bean just for advisor chain initialization.</code>
<code> </code><code>advice =</code><code>new</code> <code>prototypeplaceholderadvisor(name);</code>
<code> </code><code>addadvisoronchaincreation(advice, name);</code>
<code> </code><code>this</code><code>.advisorchaininitialized =</code><code>true</code><code>;</code>
this.advisorchaininitialized:标示是否已進行過初始化,若以初始化則不再進行初始化。然後就是将interceptornames轉化成advisor。根據interceptornames所包含的字元串到容器中進行查找,如果含有*則,則表示進行一定的比對,符合的都會納入。如官方文檔中說的:
<code><bean id=</code><code>"proxy"</code> <code>class</code><code>=</code><code>"org.springframework.aop.framework.proxyfactorybean"</code><code>></code>
<code> </code><code><property name=</code><code>"target"</code> <code>ref=</code><code>"service"</code><code>/></code>
<code> </code><code><property name=</code><code>"interceptornames"</code><code>></code>
<code> </code><code><list></code>
<code> </code><code><value>global*</value></code>
<code> </code><code></list></code>
<code> </code><code></property></code>
<code></bean></code>
<code><bean id=</code><code>"global_debug"</code> <code>class</code><code>=</code><code>"org.springframework.aop.interceptor.debuginterceptor"</code><code>/></code>
<code><bean id=</code><code>"global_performance"</code> <code>class</code><code>=</code><code>"org.springframework.aop.interceptor.performancemonitorinterceptor"</code><code>/></code>
這中間頁經過了advice到advisor的轉換,如下:
<code>private</code> <code>void</code> <code>addadvisoronchaincreation(object next, string name) {</code>
<code> </code><code>// we need to convert to an advisor if necessary so that our source reference</code>
<code> </code><code>// matches what we find from superclass interceptors.</code>
<code> </code><code>advisor advisor = namedbeantoadvisor(next);</code>
<code> </code><code>if</code> <code>(logger.istraceenabled()) {</code>
<code> </code><code>logger.trace(</code><code>"adding advisor with name '"</code> <code>+ name +</code><code>"'"</code><code>);</code>
<code> </code><code>addadvisor(advisor);</code>
<code>private</code> <code>advisor namedbeantoadvisor(object next) {</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>return</code> <code>this</code><code>.advisoradapterregistry.wrap(next);</code>
<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>
這個包裹過程已經見過很多遍了,采用了擴充卡的模式。
這種方式實作的aop還是比較麻煩的,同時配置一個proxyfactorybean僅能實作對一個目标對象的攔截,要想攔截多個目标對象,需要配置多個proxyfactorybean。是以大部分還是使用spring引進的aspectj的aop方式來進行aop程式設計。