基於Java反射的定時任務設計

一、使用場景

1、不需要立即執行、立即得到結果返回。

2、如果執行失敗、需要有失敗補償機制。

3、和業務代碼解耦,適用於不同的務場景。

4、調用接口的入參、出參 統計,方便查詢。

二、執行順序

1、業務邏輯中,需要調用外部接口時,將參數組裝好,往任務表中插入一條任務記錄。(主要包括 任務類型、需要執行的類、方法、參數 等)

2、使用定時任務(xxlJob或分佈式worker)定時掃描任務表中待執行或執行失敗(未超過最大重試次數)的任務。

3、拿到待執行任務後,採用反射思想 執行任務,並記錄執行狀態和執行結果。

三、代碼示例

表設計(通用任務執行表)

主要字段

任務類型 、task_type

執行狀態、exec_status(待執行、執行成功、執行失敗)

執行的類、exec_class

執行的方法、exec_method

執行方法的參數、exec_param

執行結果、exec_result

重試次數、retry_times

 

核心代碼

定時任務調度

/**
 * 執行通用任務
 */
public void doTaskList() {
    List<Task> taskList = taskMapper.selectTaskList();
    if (CollectionUtils.isEmpty(taskList)) {
        return;
    }
    for (Task task : taskList) {
        try {
            Integer retryTimes = task.getRetryTimes();
            if (retryTimes == 1) {
                Date updateTime = task.getGmtModified();
                // 第一次重試,執行時間和上次時間間隔至少5分鐘
                if (updateTime.getTime() + 1000 * 60 * 5 > System.currentTimeMillis()) {
                    continue;
                }
            }
            if (retryTimes == 2) {
                Date updateTime = task.getGmtModified();
                // 第二次重試,執行時間和上次時間間隔至少30分鐘
                if (updateTime.getTime() + 1000 * 60 * 30 > System.currentTimeMillis()) {
                    continue;
                }
            }
            service.doTaskExec(task);
        } catch (Exception e) {
           // 執行失敗發送提醒郵件
        }
    }
}

反射執行

/**
 * 通用任務執行
 *
 * @param task 待執行的任務
 */
public void doTaskExec(Task task) throws ClassNotFoundException {
    String execClass = task.getExecClass();
    String execMethod = task.getExecMethod();
    String execParam = task.getExecParam();

    Class<?> clazz = Class.forName(execClass);
    Object object = ApplicationContextUtil.getBean(clazz);
    Method[] methods = clazz.getMethods();
    for (Method method : methods) {
        if (!method.getName().equals(execMethod)) {
            continue;
        }
        Class<?>[] paramTypes = method.getParameterTypes();
        Object[] objectValue = new Object[paramTypes.length];
        for (int i = 0; i < paramTypes.length; i++) {
            objectValue[i] = JSON.parseObject(execParam, paramTypes[i]);
        }
        Object execResult;
        try {
            execResult = reflection(object, clazz, execMethod, paramTypes, objectValue);
        } catch (Exception e) {
            log.error("外部接口返回異常:", e);
            processFailureExecResult(task, e.getMessage());
            return;
        }
        processExecResult(task, JSON.toJSONString(execResult));
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章