面向切片程式設計在很多項目中都有使用過,使用的場景也是較多。一個東西它之是以存在,肯定是解決了一些實際過程中的問題。要多去思考它存在的意義,就能了解的更深刻,才能舉一反三。
為什麼會有面向切片程式設計。程式中最讨厭的事是複制代碼,如果你發現同一段代碼,或者相似的代碼需要在多處出現,就會感覺到明顯的“壞味道”。你不得不去維護散落在各個地方的同樣邏輯,随着業務的不斷複雜或者變更,這令人難以維護。這時有些人就提出來了,這不簡單嗎,我把這些相同的代碼提取成一個方法,然後在需要的地方調用它,就可以減輕維護壓力。對于相似的代碼,抽象出一個方法相容幾個相似的邏輯,也可以提取出公共的方法。但是你還是需要在你使用的地方去顯式的調用它,這對于公共方法的調用者類是耦合的。有沒有一種無侵入式的方式,優雅的進行公共邏輯的調用呢,這就是面向切面程式設計要解決的問題。
面向切面程式設計(AOP)專門用來解決各個子產品中交叉關注點的問題,如事務管理、安全檢查、緩存等。話不多說,今天我們講下面向如何使用面向切片程式設計進行全局日志記錄。
package com.xxx.xxx.component;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
@Aspect
@Component
public class WebLogAspect {
private Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
// 定義切入點的名稱(如果多個增強處理,可以友善的使用名稱)
@Pointcut("execution(* com.xxx.xxx.controller.*.*(..))")
public void webLog(){}
@Around("webLog()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
long startTime = System.currentTimeMillis();
// 接收到請求,記錄請求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 記錄下請求内容
logger.info("URL:{},請求開始", request.getRequestURL().toString());
logger.info("Params : " + Arrays.toString(pjp.getArgs()));
// result的值就是被攔截方法的傳回值
Object result = pjp.proceed();
logger.info("URL:{},請求結束,result:{} ", request.getRequestURL().toString(), JSON.toJSONString(result));
logger.info("Cost Time : {}ms" ,(System.currentTimeMillis() - startTime));
return result;
}
}
增強處理類型:before,after,after-returning,after-throwing,around
這裡簡單的舉了一個全局日志的例子,實際中使用起來很簡單友善。這裡就會有同學又有疑問了:攔截器和AOP有什麼差別呢?
攔截器主要是攔截url的請求,進行請求的分發及路由,到真正的處理類。aop主要攔截spring中Bean的生命周期的通路,aop使用的是代理模式。