AOP是Aspect Oriented Programming的縮寫,意爲面向切面編程。經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是spring框架的一個重要內容,她經過對既有程序定義一個切入點(pointcut),而後在切入點先後切入不一樣的執行任務,常見使用場景有:打開/關閉數據庫鏈接、打開/關閉事物、記錄日誌等等。基於AOP不會破壞原來的程序邏輯,所以她能夠很好地對業務邏輯的各個不分進行抽離,從而使得業務邏輯各個部分的耦合度下降,提升程序的複用性,同時提升開發效率。java
下面介紹下,aop的簡單使用——統一處理web請求的日誌:web
一、在項目中引入AOPspring
引入方式同其餘模塊,在pom.xml中添加AOP依賴數據庫
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
在引入AOP模塊以後,通常來說,不用去作其餘配置。spring.aop.auto屬性默認是開啓的,也就是說只要引入了AOP的依賴以後,默認已經增長了@EnableAspectJAutoProxy編程
二、建立一個簡單的web請求處理框架
引入web模塊spring-boot
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
實現一個簡單的web請求處理,見下圖優化
三、實現web層的日誌切面類:WebLogAspectspa
package com.example.demo.web; import com.sun.istack.internal.logging.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import sun.nio.cs.ext.PCK; import javax.servlet.http.HttpServletRequest; import java.time.LocalTime; import java.util.Arrays; @Aspect @Component public class WebLogAspect { private Logger logger = Logger.getLogger(getClass()); @Pointcut("execution(* com.example.demo.web.*.*(..))") public void webLog(){} @Before("webLog()") public void doBefore(JoinPoint joinPoint) throws Throwable { System.out.println("before : "+LocalTime.now()); //接收到請求,記錄請求內容 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //記錄請求內容 logger.info("URL : "+request.getRequestURL().toString());logger.info("HTTP_METHOD : " + request.getMethod()); logger.info("IP : " + request.getRemoteAddr()); logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName()); logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs())); } @AfterReturning(returning = "ret", pointcut = "webLog()") public void doAfterReturning(Object ret) throws Throwable{ System.out.println("after : "+ LocalTime.now()); //處理完請求,返回內容 logger.info("RESPONCE : "+ ret); } }
實現AOP的切面主要有一下幾個因素:3d
一、使用@Aspect註解將一個Java類定義爲切面類
二、使用@Pointcut定義一個切入點,規則表達式示例以下:
任意公共方法的執行:
execution(public * *(..))
任何一個以「set」開始的方法的執行:
execution(* set*(..))
AccountService 接口的任意方法的執行:
execution(* com.xyz.service.AccountService.*(..))
定義在service包裏的任意方法的執行:
execution(* com.xyz.service.*.*(..))
定義在service包和全部子包裏的任意類的任意方法的執行:
execution(* com.xyz.service..*.*(..))
定義在pointcutexp包和全部子包裏的JoinPointObjP2類的任意方法的執行:
execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
三、根據須要在切入點的不一樣位置切入指定內容
使⽤ @Before 在切⼊點開始處切⼊內容
使⽤ @After 在切⼊點結尾處切⼊內容
使⽤ @AfterReturning 在切⼊點return內容以後切⼊內容(能夠⽤來對處理返回值作⼀些加⼯處理)
使⽤ @Around 在切⼊點先後切⼊內容,並⾃⼰控制什麼時候執⾏切⼊點⾃身的內容
使⽤ @AfterThrowing ⽤來處理當切⼊內容部分拋出異常以後的處理邏輯
四、最後,請求localhost:8888/hello?name=Sam
控制檯日誌:
五、 多個切面的優先級問題
優化:AOP切⾯的優先級
因爲經過AOP實現,程序獲得了很好的解耦,可是也會帶來⼀些問題,⽐如:咱們可能會對Web層作
多個切⾯,校驗⽤戶,校驗頭信息等等,這個時候常常會碰到切⾯的處理順序問題。
因此,咱們須要定義每一個切⾯的優先級,咱們須要 @Order(i) 註解來標識切⾯的優先級。i的值越
⼩,優先級越⾼。假設咱們還有⼀個切⾯是 CheckNameAspect ⽤來校驗name必須爲didi,咱們爲其設
置 @Order(10) ,⽽上⽂中WebLogAspect設置爲 @Order(5) ,因此WebLogAspect有更⾼的優先
級,這個時候執⾏順序是這樣的:
在 @Before 中優先執⾏ @Order(5) 的內容,再執⾏ @Order(10) 的內容
在 @After 和 @AfterReturning 中優先執⾏ @Order(10) 的內容,再執⾏ @Order(5) 的內容
因此咱們能夠這樣⼦總結: 在切⼊點前的操做,按order的值由⼩到⼤執⾏ 在切⼊點後的操做,按order的值由⼤到⼩執⾏