1. 程式人生 > >利用切面程式設計實現排程任務的時間計算

利用切面程式設計實現排程任務的時間計算

在工作中使用Scheduled註解實現任務排程

現在需要記錄排程的開始時間,實際結束時間,如果報錯則記錄報錯資訊,並記錄報錯時間。

日誌採用springboot自帶的logback,配置檔案logback-spring.xml如下

<?xml version="1.0" encoding="UTF-8" ?>

<configuration>

    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>
                %date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method:%L -%msg%n
            </pattern>
        </layout>
    </appender>

    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <encoder>
            <pattern>
                %date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method:%L -%msg%n
            </pattern>
        </encoder>
        <!--滾動策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路徑-->
            <fileNamePattern>D:/log/logbackInfo.%d.log</fileNamePattern>
        </rollingPolicy>
    </appender>

    <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>
                %date{yyyy-MM-dd HH:mm:ss.SSS} %-5level[%thread]%logger{56}.%method:%L -%msg%n
            </pattern>
        </encoder>
        <!--滾動策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--路徑-->
            <fileNamePattern>D:/log/logbackError.%d.log</fileNamePattern>
        </rollingPolicy>
    </appender>

    <root level="INFO">
        <appender-ref ref="consoleLog"/>
        <appender-ref ref="fileInfoLog"/>
        <appender-ref ref="fileErrorLog"/>
    </root>
</configuration>

同時將排程執行資訊放入mysql表中

檔案目錄如下

日誌實現核心為ScheduledTimeCal類,程式碼如下:

package com.cecgw.cq.aspect;

import com.cecgw.cq.util.TimeUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * @author:lifuyi
 * @Date: 2018/12/11 10:41
 * @Description:利用切面程式設計實現排程任務的時間計算
 */
@Aspect
@Order(-1)// 保證該AOP在@Transactional之前執行
@Component
public class ScheduledTimeCal {

    @Autowired
    JdbcTemplate jdbcTemplate;

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

    @Around(value = "execution(* com.cecgw.cq.schedule..*.*(..))")
    public void aroundLog(ProceedingJoinPoint joinPoint) {
        Date startDate = new Date();
        long startTime = startDate.getTime();
        //獲得訪問的方法名稱
        String methodName = joinPoint.getSignature().getName();
        //定義的介面方法
        Method abstractMethod = ((MethodSignature) joinPoint.getSignature()).getMethod();
        try {
            if (abstractMethod.isAnnotationPresent(Scheduled.class)) {
                logger.info("排程:" + methodName + "開始時間:"
                        + TimeUtil.formatDate(startDate, "yyyy-MM-dd HH:mm:ss"));
                joinPoint.proceed();
                Date date1 = new Date();
                long endTime = date1.getTime();
                logger.info("排程:" + methodName + "結束時間:"
                        + TimeUtil.formatDate(date1, "yyyy-MM-dd HH:mm:ss"));
                Object[] objects = {methodName, TimeUtil.formatDate(startDate, "yyyy-MM-dd HH:mm:ss"),
                        TimeUtil.formatDate(date1, "yyyy-MM-dd HH:mm:ss"), 1, endTime - startTime};
                jdbcTemplate.update("INSERT into schedule_time(schedule_name,start_time,end_time,flag,`time`) " +
                        "VALUES(?,?,?,?,?)", objects);
            } else {
                joinPoint.proceed();
            }
        } catch (Throwable throwable) {
            logger.error(errInfo((Exception) throwable));
            if (abstractMethod.isAnnotationPresent(Scheduled.class)) {
                Date date1 = new Date();
                logger.info("排程:" + methodName + "失敗時間:"
                        + TimeUtil.formatDate(date1, "yyyy-MM-dd HH:mm:ss"));
                long endTime = date1.getTime();
                Object[] objects = {methodName, TimeUtil.formatDate(startDate, "yyyy-MM-dd HH:mm:ss"),
                        TimeUtil.formatDate(date1, "yyyy-MM-dd HH:mm:ss"), 0, throwable.toString(), endTime - startTime};
                jdbcTemplate.update("INSERT into schedule_time(schedule_name,start_time,end_time,flag,err,`time`) " +
                        "VALUES(?,?,?,?,?,?)", objects);
            }
        }
    }


    public static String errInfo(Exception e) {
        StringWriter sw = null;
        PrintWriter pw = null;
        try {
            sw = new StringWriter();
            pw = new PrintWriter(sw);
            // 將出錯的棧資訊輸出到printWriter中
            e.printStackTrace(pw);
            pw.flush();
            sw.flush();
        } finally {
            if (sw != null) {
                try {
                    sw.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            if (pw != null) {
                pw.close();
            }
        }
        return sw.toString();
    }

}