天天看點

Spring AOP源碼分析(七)ProxyFactoryBean介紹

這篇文章裡面就要說說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>&lt;bean id=</code><code>"aserviceimpl"</code> <code>class</code><code>=</code><code>"com.lg.aop.service.impl.aserviceimpl"</code><code>/&gt;</code>

<code>    </code><code>&lt;bean id=</code><code>"mybeforadvice"</code> <code>class</code><code>=</code><code>"com.lg.aop.mybeforeadvice"</code><code>/&gt;</code>

<code>    </code> 

<code>    </code><code>&lt;bean</code><code>class</code><code>=</code><code>"org.springframework.aop.framework.proxyfactorybean"</code><code>&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"interfaces"</code> <code>value=</code><code>"com.lg.aop.service.aservice"</code><code>/&gt;</code>

<code>        </code><code>&lt;property name=</code><code>"target"</code><code>&gt;</code>

<code>            </code><code>&lt;ref bean=</code><code>"aserviceimpl"</code><code>/&gt;</code>

<code>        </code><code>&lt;/property&gt;</code>

<code>         </code><code>&lt;property name=</code><code>"interceptornames"</code><code>&gt; </code>

<code>            </code><code>&lt;list&gt; </code>

<code>                </code><code>&lt;value&gt;mybeforadvice&lt;/value&gt; </code>

<code>            </code><code>&lt;/list&gt; </code>

<code>        </code><code>&lt;/property&gt; </code>

<code>    </code><code>&lt;/bean&gt;</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>* &lt;p&gt;&lt;b&gt;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.&lt;/b&gt; 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>&lt;bean  id=</code><code>"aserviceimplproxy"</code> <code>class</code><code>=</code><code>"org.springframework.aop.framework.proxyfactorybean"</code><code>&gt;</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) &amp;&amp;</code>

<code>                    </code><code>this</code><code>.targetname ==</code><code>null</code> <code>&amp;&amp;</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>&lt;bean id=</code><code>"proxy"</code> <code>class</code><code>=</code><code>"org.springframework.aop.framework.proxyfactorybean"</code><code>&gt;</code>

<code>    </code><code>&lt;property name=</code><code>"target"</code> <code>ref=</code><code>"service"</code><code>/&gt;</code>

<code>    </code><code>&lt;property name=</code><code>"interceptornames"</code><code>&gt;</code>

<code>        </code><code>&lt;list&gt;</code>

<code>            </code><code>&lt;value&gt;global*&lt;/value&gt;</code>

<code>        </code><code>&lt;/list&gt;</code>

<code>    </code><code>&lt;/property&gt;</code>

<code>&lt;/bean&gt;</code>

<code>&lt;bean id=</code><code>"global_debug"</code> <code>class</code><code>=</code><code>"org.springframework.aop.interceptor.debuginterceptor"</code><code>/&gt;</code>

<code>&lt;bean id=</code><code>"global_performance"</code> <code>class</code><code>=</code><code>"org.springframework.aop.interceptor.performancemonitorinterceptor"</code><code>/&gt;</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程式設計。