注明:這篇文章一是當成學習筆記,二是給大家提供另一個快速理解學習Spring的參考。歡迎留言討論,持續更新中~
(該部分是Spring的面向切面編程AOP)
第四章 通知Bean
在軟件編程中,散布於程序中多個地點的函數被稱為“交叉事務”(日志管理、權限控制等)。從概念上來說,它們一般是與程序業務邏輯分開的,但經常卻是直接嵌入其中的。把這些交叉事務與業務邏輯分離開正式面向切面編程(AOP)的作用所在,由此引入面向切面編程...
Spring AOP的實現原理是:創建一個代理Bean,綁定通知者類(通知者類包含切面代碼與切點),匹配相應的方法,在目標代碼中嵌入執行切面的代碼。
1. 通過配置來詳細說明下Spring AOP的流程:(為了弄清楚原理,所以從配置講起,雖然目前這種方式已經不常用了,Spring 2.0提供了更加優雅的解決方案。)
代理Bean的配置,ProxyFactoryBean
<bean id="duke" class="org.springframework......ProxyFactoryBean"> <property name="target" ref="dukeTarget" /> <property name="interceptorNames" value="audienceAdvisor" /> <property name="proxyInterfaces" value="com.....Performer" /> </bean>
- target:這個屬性告訴ProxyFactoryBean哪個Bean需要被代理,通俗點就是哪個Bean需要運用切面代碼,target配置的就是目標代碼。
- interceptorNames:配置通知者,通知者可以按照如下方式配置:
<bean id="audienceAdvisor" class="org.springframe....AspectJExpressionPointcutAdvisor"> <property name="advise" ref="audienceAdvice" /> //通知者Bean,主要包含切面代碼,需要實現MethodBeforeAdvice等接口,用來表示在目標代碼執行前、后、拋出異常時候的切面代碼 <property name="expression" value="execution(* *.perform(..))" /> //AspectJ的切點匹配表達式,用來監測當目標代碼執行perform操作時候,觸發切面代碼 </bean>
- proxyInterfaces:應該代理目標代碼中的哪個接口(這個屬性其實有點重復,切點表達式基本可以匹配了,自動代理就是基於這個的升級)
2. AspectJ通過注解提供了另外一個把POJO類注解成切面的方式,比較簡潔,直接在Java代碼中寫注解,額外的配置就是在Spring的上下文中聲明一個自動代理的Bean,這樣才能知道如何把@AspectJ注解的Bean轉化為代理通知。
import org.aspectJ.lang.annotation.Aspect; @Aspect //聲明切面 public class Audience { @Pointcut("execution(* *.perform(..))") //定義切點 public void performance() {} @Before("performance()") //切點之前執行 public .... @AfterReturning("performance()") //切點之后執行 public ... @AfterThrowing("performance()") //切點拋出異常后執行 public ... }
3. Aspect這種切面聲明的方式已經直接在代碼中修改,如果要把一個普通的POJO轉化成切面,那就必須獲得源代碼,然后改變源代碼,這點是我們不希望看到的。有沒有辦法,讓我們可以引用任何Bean,作為切面呢? Spring 2.0提供了<aop:aspect>,是一個把POJO轉化為切面的優雅方案。
<aop:config> <aop:aspect ref="audience"> //切面代碼Bean <aop:pointcut id="performance" expression="excution(* *.performance(..))" /> //定義切點 <aop:before method="..." pointcut-ref="performance" /> //切面代碼具體方法,在切點前執行(下同) <aop:after-returnning method="..." pointcut-ref="performance" /> <aop:after-throwing method="..." pointcut-ref="performance" /> </aop:aspect> </aop:config>
總結:雖然Spring AOP對於大多數切面程序來說是足夠了,但Java的構造函數與普通方法是有區別的(不能被繼承),這使得Spring基於代理的AOP不能實現對象創建過程的通知。AspectJ實現的切面控制獨立於Spring,提供了Spring AOP不可能實現的多種切點類型,這方面特性一般也沒用到,有需要的朋友可以深入研究。