1. 程式人生 > >Spring AOP 切面編程記錄日誌和接口執行時間

Spring AOP 切面編程記錄日誌和接口執行時間

poi follow 大牛 日誌打印 mave ont type exceptio throw

最近客戶現在提出系統訪問非常慢,需要優化提升訪問速度,在排查了nginx、tomcat內存和服務器負載之後,判斷是數據庫查詢速度慢,進一步排查發現是因為部分視圖和表查詢特別慢導致了整個系統的響應時間特別長。知道了問題之後,就需要對查詢比較慢的接口進行優化,但哪些接口需要優化、哪些不需要呢?只能通過日誌裏的執行時間來判斷,那麽如何才能知道每一個接口的執行時間呢?

如果想學習Java工程化、高性能及分布式、深入淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友可以加我的Java高級交流:854630135,群裏有阿裏大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給大家。

?

對於這個問題,想到了使用動態代理的方式統一記錄方法的執行時間並打印日誌,這樣就能很直觀、方便的看到每個接口的執行時間了。

由於使用的是spring框架,對象都是由spring統一管理的,所以最後使用的是?Spring AOP 切面編程來統一記錄接口的執行時間,具體代碼如下(基於註解的方式):

@Component
@Aspect
public class AopLoggerAspect {

    private static final Logger logger = Logger.getLogger(AopLoggerAspect.class);

    @Pointcut("execution(public * com.iflytek.credit.platform.*.service.impl.*Impl.*(..)) || execution(public * com.iflytek.credit.platform.*.controller.*Controller.*(..))")
    public void pointCut() {

    }

    @Before("pointCut()")
    public void boBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("Method Name : [" + methodName + "] ---> AOP before ");
    }

    @After("pointCut()")
    public void doAfter(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("Method Name : [" + methodName + "] ---> AOP after ");
    }

    @AfterReturning(pointcut = "pointCut()",returning = "result")
    public void afterReturn(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("Method Name : [" + methodName + "] ---> AOP after return ,and result is : " + result.toString());
    }

    @AfterThrowing(pointcut = "pointCut()",throwing = "throwable")
    public void afterThrowing(JoinPoint joinPoint, Throwable throwable) {
        String methodName = joinPoint.getSignature().getName();
        logger.info("Method Name : [" + methodName + "] ---> AOP after throwing ,and throwable message is : " + throwable.getMessage());
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        try {
            logger.info("Method Name : [" + methodName + "] ---> AOP around start");
            long startTimeMillis = System.currentTimeMillis();
            //調用 proceed() 方法才會真正的執行實際被代理的方法
            Object result = joinPoint.proceed();
            long execTimeMillis = System.currentTimeMillis() - startTimeMillis;
            logger.info("Method Name : [" + methodName + "] ---> AOP method exec time millis : " + execTimeMillis);
            logger.info("Method Name : [" + methodName + "] ---> AOP around end , and result is : " + result.toString());
            return result;
        } catch (Throwable te) {
            logger.error(te.getMessage(),te);
            throw new RuntimeException(te.getMessage());
        }
    }

}

首先,需要創建一個類,然後在類名上加上兩個註解

@Component@Aspect
br/>@Aspect

類裏面每個方法的註解含義如下:

@Pointcut 用於定義切面的匹配規則,如果想要同事匹配多個的話,可以使用 || 把兩個規則連接起來,具體可以參照上面的代碼
@Before 目標方法執行前調用
@After 目標方法執行後調用
@AfterReturning 目標方法執行後調用,可以拿到返回結果,執行順序在 @After 之後
@AfterThrowing 目標方法執行異常時調用
@Around 調用實際的目標方法,可以在目標方法調用前做一些操作,也可以在目標方法調用後做一些操作。使用場景有:事物管理、權限控制,日誌打印、性能分析等等

以上就是各個註解的含義和作用,重點的兩個註解就是?@Pointcut 和 @Around 註解,@Pointcut用來指定切面規則,決定哪些地方使用這個切面;@Around 會實際的去調用目標方法,這樣就可以在目標方法的調用前後做一些處理,例如事物、權限、日誌等等。

需要註意的是,這些方法的執行順序:

執行目標方法前: 先進入 around ,再進入 before?
目標方法執行完成後: 先進入 around ,再進入 after ,最後進入 afterreturning?

實際的日誌信息如下,可以看出各個方法的執行順序:

技術分享圖片
?

另外,使用spring aop 需要在spring的配置文件加上以下這行配置,以開啟aop :

<aop:aspectj-autoproxy/>
同時,maven中需要加入依賴的jar包:

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.12</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.6.12</version>
</dependency>
總結一下,Spring AOP 其實就是使用動態代理來對切面層進行統一的處理,動態代理的方式有:JDK動態代理和 cglib 動態代理,JDK動態代理基於接口實現, cglib 動態代理基於子類實現。spring默認使用的是JDK動態代理,如果沒有接口,spring會自動的使用cglib動態代理。

如果想學習Java工程化、高性能及分布式、深入淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友可以加我的Java高級交流:854630135,群裏有阿裏大牛直播講解技術,以及Java大型互聯網技術的視頻免費分享給大家

Spring AOP 切面編程記錄日誌和接口執行時間