天天看點

面向切面程式設計的簡單應用

​ 面向切片程式設計在很多項目中都有使用過,使用的場景也是較多。一個東西它之是以存在,肯定是解決了一些實際過程中的問題。要多去思考它存在的意義,就能了解的更深刻,才能舉一反三。

​ 為什麼會有面向切片程式設計。程式中最讨厭的事是複制代碼,如果你發現同一段代碼,或者相似的代碼需要在多處出現,就會感覺到明顯的“壞味道”。你不得不去維護散落在各個地方的同樣邏輯,随着業務的不斷複雜或者變更,這令人難以維護。這時有些人就提出來了,這不簡單嗎,我把這些相同的代碼提取成一個方法,然後在需要的地方調用它,就可以減輕維護壓力。對于相似的代碼,抽象出一個方法相容幾個相似的邏輯,也可以提取出公共的方法。但是你還是需要在你使用的地方去顯式的調用它,這對于公共方法的調用者類是耦合的。有沒有一種無侵入式的方式,優雅的進行公共邏輯的調用呢,這就是面向切面程式設計要解決的問題。

​ 面向切面程式設計(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使用的是代理模式。