Hello,你們好,在Spring核心系列之AOP(一)中給你們講了Spring AOP的最強用的註解方式實現AOP(沒看的小夥伴最好先看一看,本文後面的例子大多都使用註解開發),這一篇就給你們分享一下Spring如何基於XML來作AOP,文章結構:html
這裏直接以一個案例的形式對xml的開發形式進行簡要分析,定義一個切面類MyAspectXML:java
public class MyAspectXML {
public void before(){
System.out.println("MyAspectXML====前置通知");
}
public void afterReturn(Object returnVal){
System.out.println("後置通知-->返回值:"+returnVal);
}
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("MyAspectXML=====環繞通知前");
Object object= joinPoint.proceed();
System.out.println("MyAspectXML=====環繞通知後");
return object;
}
public void afterThrowing(Throwable throwable){
System.out.println("MyAspectXML======異常通知:"+ throwable.getMessage());
}
public void after(){
System.out.println("MyAspectXML=====最終通知..來了");
}
}
複製代碼
注意這個類沒有加任何註解. 而後看下咱們的XML文件:express
<!-- 把切面引入到Spring容器中 -->
<bean name="myAspectXML" class="com.zdy.MyAspectXML" />
<!-- 配置AOP 切面 -->
<aop:config>
<!-- 定義切點 -->
<aop:pointcut id="pointcut" expression="execution(...)" />
<!-- 定義其餘切點函數 -->
<aop:pointcut id="otherPointcut" expression="execution(...)" />
<!-- 定義通知 order 定義優先級,值越小優先級越大-->
<aop:aspect ref="myAspectXML" order="0">
<!-- 定義通知 method 指定通知方法名,必須與MyAspectXML中的相同 pointcut 指定切點函數 -->
<aop:before method="before" pointcut-ref="pointcut" />
<!-- 後置通知 returning="returnVal" 定義返回值 必須與類中聲明的名稱同樣-->
<aop:after-returning method="afterReturn" pointcut-ref="pointcut" returning="returnVal" />
<!-- 環繞通知 -->
<aop:around method="around" pointcut-ref="pointcut" />
<!--異常通知 throwing="throwable" 指定異常通知錯誤信息變量,必須與類中聲明的名稱同樣-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="throwable"/>
<!-- method : 通知的方法(最終通知) pointcut-ref : 通知應用到的切點方法 -->
<aop:after method="after" pointcut-ref="otherPointcut"/>
</aop:aspect>
</aop:config>
複製代碼
你們能夠看到,<aop:aspect>這個標籤其實對應的就是MyAspectXML類,而後在類中組裝各類加強(建言)。其實若是在上一篇裏對註解的那種形式比較瞭解的話,能夠看到XML註解無非就是把各類元素放到了XML裏去組裝。效果是同樣同樣的。xml配置在工做中用的比較少,通常都是註解。因此你們看了瞭解下就OK了 。也是比較簡單的。而後給XMl配置的傳送門,參考了看下吧:緩存
首先說一下,設計到優先級問題的前提是,加強的Pointcut有交集。 Aspect優先級分兩種,一種是一個Aspect中定義多個加強。另外一種是不一樣的Aspect中的多個加強.我先說下結論,而後針對不一樣狀況搞倆例子。bash
@Aspect
public class AspectOne {
/** * Pointcut定義切點函數 */
@Pointcut("execution(...)")
private void myPointcut(){}
@Before("myPointcut()")
public void beforeOne(){
System.out.println("前置通知....執行順序1");
}
@Before("myPointcut()")
public void beforeTwo(){
System.out.println("前置通知....執行順序2");
}
@AfterReturning(value = "myPointcut()")
public void AfterReturningThree(){
System.out.println("後置通知....執行順序3");
}
@AfterReturning(value = "myPointcut()")
public void AfterReturningFour(){
System.out.println("後置通知....執行順序4");
}
}
複製代碼
打印結果:ide
前置通知....執行順序1
前置通知....執行順序2
後置通知....執行順序4
後置通知....執行順序3
複製代碼
@Aspect
public class AspectOne implements Ordered {
/** * Pointcut定義切點函數 */
@Pointcut("execution(...)")
private void myPointcut(){}
@Before("myPointcut()")
public void beforeOne(){
System.out.println("前置通知..AspectOne..執行順序1");
}
@Before("myPointcut()")
public void beforeTwo(){
System.out.println("前置通知..AspectOne..執行順序2");
}
@AfterReturning(value = "myPointcut()")
public void AfterReturningThree(){
System.out.println("後置通知..AspectOne..執行順序3");
}
@AfterReturning(value = "myPointcut()")
public void AfterReturningFour(){
System.out.println("後置通知..AspectOne..執行順序4");
}
/** * 定義優先級,值越低,優先級越高 * @return */
@Override
public int getOrder() {
return 0;
}
}
//切面類 AspectTwo.java
@Aspect
public class AspectTwo implements Ordered {
/** * Pointcut定義切點函數 */
@Pointcut("execution(...)")
private void myPointcut(){}
@Before("myPointcut()")
public void beforeOne(){
System.out.println("前置通知....執行順序1--AspectTwo");
}
@Before("myPointcut()")
public void beforeTwo(){
System.out.println("前置通知....執行順序2--AspectTwo");
}
@AfterReturning(value = "myPointcut()")
public void AfterReturningThree(){
System.out.println("後置通知....執行順序3--AspectTwo");
}
@AfterReturning(value = "myPointcut()")
public void AfterReturningFour(){
System.out.println("後置通知....執行順序4--AspectTwo");
}
/** * 定義優先級,值越低,優先級越高 * @return */
@Override
public int getOrder() {
return 1;
}
}
複製代碼
輸出結果:函數
前置通知..AspectOne..執行順序1
前置通知..AspectOne..執行順序2
前置通知....執行順序1--AspectTwo
前置通知....執行順序2--AspectTwo
後置通知....執行順序4--AspectTwo
後置通知....執行順序3--AspectTwo
後置通知..AspectOne..執行順序4
後置通知..AspectOne..執行順序3
複製代碼
好了,關於AspectJ的優先級分享完了,你們參照着前面總結的結論,再看下兩個例子,應該是能夠搞懂的。不過說實在的,用的比較少。(^_^)post
Spring AOP的實際運用場景其實仍是比較多的,別的不說,Spring本身的事務管理其實就運用了AOP,這裏我來一個相對而言靠近開發者的案例,性能監控。其實說是性能監控,沒那麼高大上,無非就是計算一下一個Web接口調用的時間。而後打日誌或者寫入到其餘監控平臺(granafa等).廢話少說,直接擼代碼:性能
先定義一個實體類,用於存監控的一些信息:this
public class MonitorData {
//類名
private String className;
//方法名
private String methodName;
//消耗時間
private String consumeTime;
//記錄時間
private Date logTime;
//gettter setter toString什麼的省略
....
}
複製代碼
@Aspect
@Component
public class MonitorAspectJ {
/** * 定義切點函數,過濾controller包下的名稱以Controller結尾的類全部方法 */
@Pointcut("execution(* com..*Controller.*(..))")
void timer() {
}
@Around("timer()")
public Object logTimer(ProceedingJoinPoint thisJoinPoint) throws Throwable {
MonitorData monitorData=new MonitorData();
//獲取目標類名稱
String clazzName = thisJoinPoint.getTarget().getClass().getName();
//獲取目標類方法名稱
String methodName = thisJoinPoint.getSignature().getName();
//記錄類名稱
monitorData.setClassName(clazzName);
//記錄對應方法名稱
monitorData.setMethodName(methodName);
//記錄時間
monitorData.setLogTime(new Date());
// 計時並調用目標函數
long start = System.currentTimeMillis();
Object result = thisJoinPoint.proceed();
Long time = System.currentTimeMillis() - start;
//設置消耗時間
monitorData.setConsumeTime(time.toString());
//把monitorTime記錄的信息上傳給監控系統,並無實現,須要自行實現便可
//MonitoruUtils.report(monitorTime)
System.out.println(monitorData.toString());
return result;
}
}
複製代碼
其實仍是比較好理解的,無非就是在把全部以Controller結尾的類的全部方法上加上環繞,記錄時間。而後存儲下來(我這是打印了一下).
AOP的應用遠不止這兩種,諸如緩存,權限驗證、內容處理、事務控制等均可以使用AOP實現,其中事務控制Spring中提供了專門的處理方式,限於篇幅就先聊到這。
Spring AOP的底層實現有兩種可選,一種是JDK動態代理,一種是CGLib動態代理。先說下結論,若是要代理的target有接口,則默認採用JDK動態代理。若是沒有,則採用CGLib動態代理。固然也能夠強制指定使用CGLib動態代理。方法:
若是要代理的對象沒有實現任何接口,則必須使用CGLIb代理,若是有,則可使用JDK代理和CGLib代理,至於爲何,其實有點一言難盡,這裏不許備展開。後期有機會專門寫動態代理了再展開說。對於咱們在Web項目中經常使用的單例類,儘可能使用CGLib動態代理來實現Spring AOP.
CGlib特色以下:字節碼技術,啓動慢,爲每個方法作索引,效率高。 而JDK動態代理特色則是:啓動快,每一個方法經過反射調用,效率低,方法沒有索引。
好了,Spring AOP和你們分享完了,有點遺憾的是關於它底層的JDK動態代理和CGLib動態代理沒有展開來說。不過不要緊,後期有時間必定專門出一篇動態代理的文章,經過Spring AOP 的兩篇文章,但願你們至少可以在使用層面掌握好AOP這種思想,並能運用到工做當中去。Spring,以及Spring boot其實不少地方都運用到了Spring AOP,後面的文章若是涉及到會給你們點出來。Over ,Have a good day .