Spring全家桶實(shí)踐-AOP日志

簡介

SLF4J是Simple Logging Facade for Java的縮寫。它主要提供了Java目前現(xiàn)有日志框架的簡單抽象。它使用戶能夠使用單個依賴項(xiàng)處理任何日志框架,例如:Log4j,Logback和JUL。也可以在運(yùn)行/部署時遷移到對應(yīng)的日志記錄框架。

優(yōu)點(diǎn)

*可以在部署時遷移到所需的日志記錄框架。
*提供了對所有流行的日志框架的綁定。
*支持參數(shù)化日志記錄消息。
*程序和日志記錄框架分離。
*提供了一個簡單的日志遷移工具。

常規(guī)使用

參看slf4j官網(wǎng)網(wǎng)站
參看易佰教程

這個模塊需要的知識貯備

實(shí)際項(xiàng)目使用自定義注解和aop的方式來實(shí)現(xiàn)操作訪問記錄功能

自定義注解

參看Java的注解

AOP

Spring AOP簡單樣例
暫時不記錄數(shù)據(jù)庫,等學(xué)習(xí)完jpa后,在記錄到數(shù)據(jù)中。

實(shí)踐

maven文件

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

目錄結(jié)構(gòu)

image.png

源碼

定義記錄那些信息Log類(Log.java)

package com.springboot.action.saas.common.logging.domain;

import lombok.Data;

import java.sql.Timestamp;

@Data
public class Log {
    //描述
    private String description;
    //方法名
    private String method;
    //參數(shù)
    private String params;
    //日志類型
    private String logType;
    //請求ip
    private String requestIp;
    //請求耗時
    private Long time;
    //異常詳細(xì)
    private String exceptionDetail;
    //請求實(shí)踐
    private Timestamp createTime;
    //構(gòu)造函數(shù)(代參)
    public Log(String logType, Long time) {
        this.logType = logType;
        this.time = time;
    }
}

日志記錄業(yè)務(wù)接口(LogService.java)

package com.springboot.action.saas.common.logging.service;

import com.springboot.action.saas.common.logging.domain.Log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.scheduling.annotation.Async;

/*
* 日志記錄業(yè)務(wù)
*
*/
public interface LogService {
    /*
    * 記錄日志,異步執(zhí)行,不影響正常業(yè)務(wù)流程
    * 參數(shù) joinPoint 切面方法的信息,當(dāng)前切入點(diǎn)各種信息
    *     log 要記錄的日志信息有那些
    * */
    @Async
    void save(ProceedingJoinPoint joinPoint, Log log);
}

日志記錄業(yè)務(wù)接口實(shí)現(xiàn)(LogServiceImpl.java)

package com.springboot.action.saas.common.logging.service.impl;

import com.springboot.action.saas.common.logging.domain.Log;
import com.springboot.action.saas.common.logging.service.LogService;
import com.springboot.action.saas.common.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Service
public class LogServiceImpl implements LogService {
    /*
    * 記錄日志接口實(shí)現(xiàn)
    **/
    @Override
    public void save(ProceedingJoinPoint joinPoint, Log log) {
        //獲取request 請求對象
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes())
                .getRequest();
        //getSignature獲取切面相關(guān)信息,比如方法名、目標(biāo)方法參數(shù)等信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //獲取抽象類(代理對象)方法
        Method method = signature.getMethod();
        //返回該元素的指定類型的注釋,這里是Log注解
        com.springboot.action.saas.common.logging.annotation.Log aopLog = method.getAnnotation(com.springboot.action.saas.common.logging.annotation.Log.class);
        //獲取注解傳遞的參數(shù)
        if (log != null) {
            log.setDescription(aopLog.value());
        }
        //通過最笨的反射方法,獲取方法路徑
        String methodName = joinPoint.getTarget().getClass().getName()+"."+signature.getName()+"()";
        log.setMethod(methodName);
        //參數(shù)處理
        //獲取參數(shù)值
        Object[] argValues = joinPoint.getArgs();
        //獲取參數(shù)名
        String[] argNames = ((MethodSignature)joinPoint.getSignature()).getParameterNames();
        //組織參數(shù)列表
        String params = "{";
        if(argValues != null){
            for (int i = 0; i < argValues.length; i++) {
                params += " " + argNames[i] + ": " + argValues[i];
            }
        }
        log.setParams(params + " }");
        //獲取IP地址
        log.setRequestIp(StringUtils.getIP(request));
        //輸出下日志到控制臺
        System.out.println(log.toString());
    }
}

配置切點(diǎn)和切點(diǎn)對應(yīng)的動作(好多文檔都說是通知)
LogAspect.java

package com.springboot.action.saas.common.logging.aspect;

import com.springboot.action.saas.common.logging.domain.Log;
import com.springboot.action.saas.common.logging.service.LogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LogAspect {
    //日志業(yè)務(wù)
    @Autowired
    private LogService logService;
    //當(dāng)前時間
    private long currentTime = 0L;

    /**
     * 配置切入點(diǎn), 匹配連接點(diǎn)的方法是否有Log注解,定義切點(diǎn)
     */
    @Pointcut("@annotation(com.springboot.action.saas.common.logging.annotation.Log)")
    public void logPointcut() {
        // 該方法無方法體,主要為了讓同類中其他方法使用此切入點(diǎn)
    }

    /**
     * 配置環(huán)繞通知,使用在方法logPointcut()上注冊的切入點(diǎn),具體要通知在什么條件下執(zhí)行和執(zhí)行什么動作
     *
     * @param joinPoint join point for advice
     */
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint){
        //返回值
        Object result = null;
        //獲取當(dāng)前時間
        currentTime = System.currentTimeMillis();
        try {
            //執(zhí)行目標(biāo)方法
            result = joinPoint.proceed();
        } catch (Throwable e) {
            //拋異常
            throw new RuntimeException(e.getMessage());
        }
        //創(chuàng)建日志對象
        Log log = new Log("INFO",System.currentTimeMillis() - currentTime);
        //記錄日志
        logService.save(joinPoint, log);
        //返回目標(biāo)方法的返回值
        return result;
    }

    /**
     * 配置異常通知,異常的日志也要記錄
     *
     * @param joinPoint join point for advice
     * @param e exception
     */
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        //創(chuàng)建日志對象
        Log log = new Log("ERROR",System.currentTimeMillis() - currentTime);
        //異常設(shè)置
        log.setExceptionDetail(e.getMessage());
        //記錄異常
        logService.save((ProceedingJoinPoint)joinPoint, log);
    }
}

REST接口

/**
     * 顯示所有Member,請求url:"http://xxx/member/v1/findall"
     *
     * @return List
     */
    //這里增加了自定義日志注解
    @Log("獲取全部用戶列表")
    @RequestMapping(value = "/v1/findall")
    public List<Member> findAllMember() {
        return memberService.findAllMember();
    }

實(shí)際運(yùn)行效果
請求

http://localhost:8080/member/v1/findall

瀏覽器

{"success":true,"code":0,"data":[{"id":1,"phone":null,"password":null,"nickname":"demo1","email":null,"ctime":null,"utime":null,"last_login_time":null,"last_login_ip":null,"invite_code":null,"is_active":null,"is_delete":null},{"id":2,"phone":null,"password":null,"nickname":"demo2","email":null,"ctime":null,"utime":null,"last_login_time":null,"last_login_ip":null,"invite_code":null,"is_active":null,"is_delete":null}],"message":"","currentTime":1564631416588}

控制臺

Log(description=獲取全部用戶列表, method=com.springboot.action.saas.modules.user.controller.MemberController.findAllMember(), params={ }, logType=INFO, requestIp=127.0.0.1, time=4, exceptionDetail=null, createTime=null)

打tag 1.0.4版本,提交代碼。

git tag -a v1.0.4 -m "實(shí)現(xiàn)AOP日志信息獲取"

git push origin v1.0.4

github地址:https://github.com/horacepei/springsaas

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容