1、簡介java
何爲AOP,通俗的將就是給某些方法執行以前、執行以後等動做發生的時候執行某些操做,在執行這些操做的時候能夠獲取執行方法的相關信息,簡化程序開發中老是重複的東西,好比方法入參出參的日誌打印,用戶訪問權限校驗,事務控制等。spring
2、術語json
通知(advice):切面的工做被稱爲通知。通俗點:何時怎麼幹啥事。編輯器
1.前置通知(before):在目標方法被調用以前調用通知功能。代理
2.後置通知(after):在目標方法完成以後調用通知,此事不會關心方法的輸出是什麼。日誌
3.返回通知(after-returning):在目標方法成功執行以後調用通知。code
4.異常通知(after-throwing):在目標方法跑出異常後調用通知。對象
5.環繞通知(around):通知包裹了被通知的方法,在被通知的方法調用以前和調用以後執行自定義的行爲。生命週期
鏈接點(joinpoint):使用通知的地方。事務
切點(pointcut):匹配通知所要織入的一個或多個鏈接點。
切面(aspect):通知和切點的結合定義切面的所有內容,它是什麼,在什麼時候何處完成其功能。
引入(introduction):能夠向現有的類添加新方法和屬性。
織入(weaving):把切面應用到目標對象並建立新的代理對象的過程。切面在制定的鏈接點被織入到目標對象中,在目標對象的生命週期裏有多個點能夠織入:
1.編譯期:切面在目標類編譯時織入,這種方式須要特殊的編譯器,AspectJ的織入編輯器就是以這種方式織入切面的。
2.類加載期:切面在目標類加載到JVM時織入,這種方式須要特殊的類加載器(ClassLoader),它能夠在目標類被引入應用以前加強該目標類的字節碼。
3.運行期:切面在應用運行的某個時刻被織入,通常狀況下,在織入切面時,AOP容器會爲目標對象動態的建立一個代理對象,SpringAOP就是以這種方式織入切面的。
3、spring對AOP的支持
spring提供了4種類型的AOP支持:
1.基於代理的經典SpringAOP
2.純POJO切面
3.@AspectJ註解驅動的切面
4.注入式AspectJ切面
前三種是springAOP實現的變體,SpringAOP構建在動態代理的基礎之上,所以,spring對AOP的支持侷限於方法攔截。
4、spring只支持方法界別的鏈接點
由於spring是基於動態代理,因此孩子恩可以支持方法級別的aop。AspectJ和JBoss,除了方法切點,還提供了字段和構造器接入點。spring缺乏字段鏈接點的支持,沒法讓咱們建立細粒度的通知,例如攔截對象字段的修改,並且他不支持構造器鏈接點,咱們就沒法再bean建立時應用通知。
5、切點表達式
execution(* sundsystem.CompactDisc.playTrack(int))
第一個* 返回任意類型
sundsystem.CompactDisc 方法所屬的類型
playTrack 方法
int 接受int類型的參數
6、demo
註解:
package com.pz.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSON; @Aspect @Component public class LogAspect { private static Logger logger = LoggerFactory.getLogger(LogAspect.class); @Pointcut("execution(public * com.pz.service..*.*(..))") public void logPoint(){} @Before("logPoint()") public void logBefor(JoinPoint joinPoint){ String method = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); String param = JSON.toJSONString(args); logger.info("[前置通知][{}] param:{}", method, param); } @After("logPoint()") public void logAfter(JoinPoint joinPoint){ String method = joinPoint.getSignature().getName(); Object [] args = joinPoint.getArgs(); String param = JSON.toJSONString(args); logger.info("[後置通知][{}] result:{}", method, param); } @AfterReturning(pointcut="logPoint()", returning="result") public void logAfterReturning(JoinPoint joinPoint, Object result){ String method = joinPoint.getSignature().getName(); String response = JSON.toJSONString(result); logger.info("[返回通知][{}] return:{}", method, response); } @AfterThrowing(pointcut="logPoint()", throwing="e") public void logAfterThrowing(JoinPoint joinPoint, Exception e){ String method = joinPoint.getSignature().getName(); logger.error("[異常通知][{}] exception:{}", method, e.getMessage()); } @Around("logPoint()") public Object logArount(ProceedingJoinPoint pjp) throws Throwable{ Object result = null; String param = JSON.toJSONString(pjp.getArgs()); String method = pjp.getSignature().getName(); try{ logger.info("[環繞通知][{}] param:{}", method, param); result = pjp.proceed(); logger.info("[環繞通知][{}] result:{}", method, JSON.toJSON(result)); }catch(Exception e){ logger.error("[環繞通知][{}] exception:{}", method, e.getMessage()); throw new RuntimeException(e); } logger.info("[環繞通知][{}] return:{}", method, JSON.toJSON(result)); return result; } }