Spring Boot 入門(五):集成 AOP 進行日誌管理

本篇文章是接着 Spring boot 入門(四):集成 Shiro 實現登錄認證和權限管理寫的,按照前面幾篇博客的教程,能夠搭建一個簡單的項目,主要包含了 Pagehelper+MyBatis 分頁查詢,Generator 代碼自動生成器,Shiro登陸及權限管理。本篇博客主要是集成 AOP 進行日誌管理java

1.導入 jar 包

<!-- aop -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
複製代碼

2.配置 Logback-spring 文件

關於 Logback-spring 的配置網上不少,隨便copy一份基本上就能使用,Logback-spring.xml 中主要配置了下列內容spring

  • (1).日誌寫道控制檯
  • (2).日誌寫道本地文件中
  • (3).日誌級別
  • (4).日誌生成方式(按照日期滾動生成,仍是按照日期單獨生成)
  • (5).日誌來源的配置,通常直接配置到 Control

我也是直接在copy了一份,代碼以下bash

<?xml version="1.0" encoding="UTF-8"?>
<configuration  scan="true" scanPeriod="60 seconds" debug="false">
    <contextName>logback</contextName>
<!--
    &lt;!&ndash; 文件輸出格式 &ndash;&gt;
    <property name="PATTERN" value="%-12(%d{yyyy-MM-dd HH:mm:ss.SSS}) |-%-5level [%thread] %c [%L] -| %msg%n" />
    &lt;!&ndash; test文件路徑 &ndash;&gt;
    <property name="TEST_FILE_PATH" value="c:/log" />

    -->

    <!--輸出到控制檯-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <!--按天生成日誌-->
    <appender name="logFile"  class="ch.qos.logback.core.rolling.RollingFileAppender">
        <Prudent>true</Prudent>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <FileNamePattern>
                applog/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log
            </FileNamePattern>
        </rollingPolicy>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>
                %d{yyyy-MM-dd HH:mm:ss} -%msg%n
            </Pattern>
        </layout>
    </appender>

    <logger name="com.tswc.edu" additivity="false">
        <appender-ref ref="console"/>
        <appender-ref ref="logFile" />
    </logger>

    <root level="error">
        <appender-ref ref="console"/>
        <appender-ref ref="logFile" />
    </root>

</configuration>

複製代碼

這裏用戶也能夠配置多個級別使用於多個環境,對每一個日誌級別進行配置不一樣的屬性,而後在 Application.xml 中選擇不一樣的級別環境。在實際項目開發的過程當中,通常配置2個環境,開發環境,生產環境。在開發環境中,只須要配置日誌輸出到控制檯,便於開發人員調試。生成環境相反,須要配置日誌輸出到文件,控制檯儘可能不要輸出日誌,這樣能夠減小控制檯對虛擬機內存的消耗,一旦產生 Bug ,用戶查詢日誌文件便可app

上述代碼中即配置了日誌輸出到控制檯,也配置了日誌輸出到日誌文件異步

3.配置日誌級別

只須要在 Application.xml 中配置便可:spring-boot

日誌級別分爲5個等級,debug<info<warn<Error<Fatal,其中經常使用的級別爲:debug和info

  • debug 級別最低,能夠隨意的使用於任何以爲有利於在調試時更詳細的瞭解系統運行狀態的東東;
  • info 重要,輸出信息:用來反饋系統的當前狀態給最終用戶的; 後三個,警告、錯誤、嚴重錯誤,這三者應該都在系統運行時檢測到了一個不正常的狀態。
  • warn, 可修復,系統可繼續運行下去;
  • Error, 可修復性,但沒法肯定系統會正常的工做下去;
  • Fatal, 至關嚴重,能夠確定這種錯誤已經沒法修復,而且若是系統繼續運行下去的話後果嚴重。

4.編寫日誌類

@Aspect
@Component
public class WebLogAspect {

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

    @Pointcut("execution( * com.tswc.edu.controller.*.*(..))")//兩個..表明全部子目錄,最後括號裏的兩個..表明全部參數
    public void logPointCut() {
    }

    //切點
    @Pointcut("@annotation(com.tswc.edu.annotation.Log)")
    public void logPointCutLog() {
    }

    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        // 接收到請求,記錄請求內容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 記錄下請求內容
        logger.info("請求地址 : " + request.getRequestURL().toString());
        //logger.info("方法描述 : " + );
        logger.info("HTTP METHOD : " + request.getMethod());
        // 獲取真實的ip地址
        //logger.info("IP : " + IPAddressUtil.getClientIpAddress(request));
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
                + joinPoint.getSignature().getName());
        logger.info("參數 : " + Arrays.toString(joinPoint.getArgs()));
//        loggger.info("參數 : " + joinPoint.getArgs());

    }

    @AfterReturning(returning = "ret", pointcut = "logPointCut()")// returning的值和doAfterReturning的參數名一致
    public void doAfterReturning(Object ret) throws Throwable {
        // 處理完請求,返回內容(返回值太複雜時,打印的是物理存儲空間的地址)
        logger.debug("返回值 : " + ret);
    }

    @Around("logPointCut()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object ob = pjp.proceed();// ob 爲方法的返回值
        logger.info("耗時 : " + (System.currentTimeMillis() - startTime));
        return ob;
    }

    @Around("logPointCutLog()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 執行方法
        Object result = point.proceed();
        // 得到註解
        Log controllerLog = getAnnotationLog(point);
        if (controllerLog == null) {
            return null;
        }
        String action = controllerLog.value();
        logger.info("請求目的:"+action);
        return result;
    }
    /**
     * 是否存在註解,若是存在就獲取
     */
    private static Log getAnnotationLog(JoinPoint joinPoint) throws Exception {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            //System.out.println("123:"+method.getAnnotation(Log.class).value());
            return method.getAnnotation(Log.class);
        }
        //System.out.println("1234:"+method.getAnnotation(Log.class).value());
        return null;
    }
}
複製代碼

這是個通用類,主要約定控制檯或者日誌文件中日誌的格式,關於此公共類,網上有大量的講解,這裏就不詳細說明了。post

再次啓動項目,控制檯將輸出日誌,並將日誌寫入到文件中:ui

5.新增長部分

其中自定義日誌文件能夠不要,這裏用戶本身定義了日誌輸出的說明部分

自定義了 @Log 註記的識別,並配置一些文件說明,那麼在請求到這個類的時候,日誌中將輸出文章描述部分

自定義配置文件的代碼:spa

  • Log
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
//自定義註解類   ArchivesLog.java(獲取Controller描述用的)
public @interface Log {
    String value() default "";
}
複製代碼
  • LogAspect
public class LogAspect {
    private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
    //切點
    @Pointcut("@annotation(com.tswc.edu.annotation.Log)")
    public void logPointCut() {
    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        long beginTime = System.currentTimeMillis();
        // 執行方法
        Object result = point.proceed();
        // 執行時長(毫秒)
        long time = System.currentTimeMillis() - beginTime;
        //異步保存日誌
        //saveLog(point, time);
        return result;
    }

}
複製代碼

其中LogAspect中也能夠寫一些對日誌進行 CRUD 的業務邏輯操做,大多數狀況下,此處能夠將日誌的保存邏輯寫入到此類中。debug

6.問題

本項目在啓動的時候,報了一個關於日誌的警告,沒有找到解決方案

項目中並無用到log4j,不知道爲何會警告,項目中缺乏log4j的配置文件,若是有大神知道緣由,歡迎留言

相關文章
相關標籤/搜索