定时任务模块设计及代码

定时任务模块相关

设计思路是:用一个数据库表存下需要执行的定时任务的 编码/名称/描述/corn表达式/调用的链接 等信息,新增一条定时任务表的数据时,将这个定时任务注册到quartz中即可。

1.通用代码

在这里插入图片描述

①JobFactory

package com.sinoccdc.devops.scheduler.utils;

//import org.quartz.spi.TriggerFiredBundle;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

@Component
public class JobFactory extends AdaptableJobFactory {
	@Autowired
	private AutowireCapableBeanFactory capableBeanFactory;

	@Override
	protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
		// 调用父类的方法
		Object jobInstance = super.createJobInstance(bundle);
		// 进行注入
		capableBeanFactory.autowireBean(jobInstance);
		return jobInstance;
	}
}

JobStatusEnum状态的枚举类

package com.sinoccdc.devops.scheduler.utils;

public enum JobStatusEnum {
	WAITING,
	PAUSED,
	RUNNING,
	BLOCKED,
	ERROR;

	public String getCode() {
		if(this==WAITING) {
			return "waiting";
		}else if(this==PAUSED) {
			return "paused";
		}else if(this==RUNNING) {
			return "running";
		}else if(this==BLOCKED) {
			return "blocked";
		}else if(this==ERROR) {
			return "error";
		}
		return null;
	}
	
	public String getName() {
		if(this==WAITING) {
			return "等待";
		}else if(this==PAUSED) {
			return "暂停";
		}else if(this==RUNNING) {
			return "运行";
		}else if(this==BLOCKED) {
			return "阻塞";
		}else if(this==ERROR) {
			return "错误";
		}
		return null;
	}
}

QuartzConfigration

package com.sinoccdc.devops.scheduler.utils;

import java.io.IOException;
//import java.util.Properties;
import java.util.Properties;

//import org.quartz.Scheduler;
//import org.quartz.spi.JobFactory;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;


@Configuration
public class QuartzConfigration {
	@Autowired
	private JobFactory jobFactory;
	
	@Bean
	public SchedulerFactoryBean schedulerFactoryBean() {
		SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
		try {
			schedulerFactoryBean.setOverwriteExistingJobs(true);
			schedulerFactoryBean.setQuartzProperties(quartzProperties());
			schedulerFactoryBean.setJobFactory(jobFactory);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return schedulerFactoryBean;
	}
	// 指定quartz.properties,可在配置文件中配置相关属性
	@Bean
	public Properties quartzProperties() throws IOException {
		PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
		propertiesFactoryBean.setLocations(new ClassPathResource("/quartz.properties"));
		propertiesFactoryBean.afterPropertiesSet();
		return propertiesFactoryBean.getObject();
	}
	// 创建schedule
    @Bean(name = "scheduler")
	public Scheduler scheduler() {
		return schedulerFactoryBean().getScheduler();
	}
	
}

QuartzManager

package com.sinoccdc.devops.scheduler.utils;

import java.util.List;

import com.sinoccdc.devops.domain.application.scheduler.SchedulerTaskService;
import com.sinoccdc.devops.scheduler.SchedulerTask;
import com.sinoccdc.devops.scheduler.SchedulerTaskRepository;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.DateBuilder;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;



/*
import org.springframework.data.domain.Page;
import com.sinoccdc.fiveNet.dao.TaskDao;
import com.sinoccdc.fiveNet.pojo.TaskPo;
import com.chinatransinfo.customCommon.scheduler.dao.TaskDao;
import com.chinatransinfo.customCommon.scheduler.pojo.TaskPo;*/

@Component
public class QuartzManager {
    @Autowired
    private Scheduler scheduler;

    @Autowired
    private SchedulerTaskService schedulerTaskService;
    @Autowired
    private SchedulerTaskRepository schedulerTaskRepository;
	/**
	 * 初始化调度
	 * @throws Exception
	 */
	public void initSchedule() throws Exception {
		// 这里获取任务信息数据
//        List<TaskPo> jobList = taskDao.getTaskList(null, null, null);
        List<SchedulerTask> jobList = schedulerTaskRepository.findAll();
        for (SchedulerTask task : jobList) {
            if (JobStatusEnum.RUNNING.getCode().equals(task.getJobStatus())) {
                this.addJob(task);
            }
        }
	}
	/**
     * 添加任务*/    
    @SuppressWarnings("unchecked")
    public void addJob(SchedulerTask task) {
        try {
            // 创建jobDetail实例,绑定Job实现类
            // 指明job的名称,所在组的名称,以及绑定job类
            Class<? extends Job> jobClass = (Class<? extends Job>) (Class.forName(task.getBeanClass()).newInstance().getClass());
         // 任务名称和组构成任务key
            //JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(task.getJobCode(), task.getJobGroup()).build();
            //任务的主键构成任务key
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(task.getJobCode(), task.getJobGroup()).build();
            // 定义调度触发规则
            Trigger trigger;
            if(StringUtils.isEmpty(task.getCronExpression())) {
            	trigger = TriggerBuilder.newTrigger().withIdentity(task.getJobCode(), task.getJobGroup())// 触发器key
            			.startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
            			.withSchedule(
            					SimpleScheduleBuilder.simpleSchedule()
            					.withIntervalInSeconds(3)
            					.withRepeatCount(0)).build();
            }else {
            	// 使用cornTrigger规则
            	trigger = TriggerBuilder.newTrigger().withIdentity(task.getJobCode(), task.getJobGroup())// 触发器key
                        .startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
                        .withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression())).startNow().build();
            }
        	// 把作业和触发器注册到任务调度中         
        	scheduler.scheduleJob(jobDetail, trigger);
            // 启动
            if (!scheduler.isShutdown()) {
                scheduler.start();
                task.setJobStatus(JobStatusEnum.RUNNING.getCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 暂停任务
     * @param task
     * @throws SchedulerException
     */
    public void pauseJob(SchedulerTask task) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(task.getJobCode(), task.getJobGroup());
        scheduler.pauseJob(jobKey);
        task.setJobStatus(JobStatusEnum.PAUSED.getCode());
        try {
			schedulerTaskService.saveSchedulerTask(task);
		} catch (Exception e) {
			e.printStackTrace();
		}
    }
    /**
     * 恢复任务
     * @param task
     * @throws SchedulerException
     */
    public void resumeJob(SchedulerTask task) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(task.getJobCode(), task.getJobGroup());
        scheduler.resumeJob(jobKey);
        task.setJobStatus(JobStatusEnum.RUNNING.getCode());
        try {

			schedulerTaskService.saveSchedulerTask(task);

		} catch (Exception e) {
			e.printStackTrace();
		}
    }
    /**
     * 删除任务
     * @param task
     * @throws SchedulerException
     */
    public void deleteJob(SchedulerTask task) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(task.getJobCode(), task.getJobGroup());
        scheduler.deleteJob(jobKey);
        try {
            schedulerTaskService.deleteSchedulerTaskById(task.getId());

		} catch (Exception e) {
			e.printStackTrace();
		}
    }
    /**
     * 立即出发job
     * @param task
     * @throws SchedulerException
     */
    public void runJobNow(SchedulerTask task) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(task.getJobCode(), task.getJobGroup());
        scheduler.triggerJob(jobKey);
    }
    
    /**
     * 更新任务cron
     * @param task
     * @throws SchedulerException
     */
    public void updateJobCron(SchedulerTask task) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobCode(), task.getJobGroup());
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCronExpression());
        trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
        scheduler.rescheduleJob(triggerKey, trigger);
    }

}

ScheduleJobInitListener

package com.sinoccdc.devops.scheduler.utils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(value = 1)
public class ScheduleJobInitListener implements CommandLineRunner{
	@Autowired
    QuartzManager scheduleJobService;
	@Override
	public void run(String... args) throws Exception {
		try {
            scheduleJobService.initSchedule();
        } catch (Exception e) {
            e.printStackTrace();
        }
	}
}

TaskRedisData

package com.sinoccdc.devops.scheduler.utils;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.io.Serializable;
import java.util.Date;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class TaskRedisData implements Serializable {

    //完成百分比
    String completePercent;

    //完成时间
    Date completeTime;

    //发生错误的标识
    String failTag;

    //其他信息
    String message;
}

TaskStandard

package com.sinoccdc.devops.scheduler.utils;

//任务规范
public interface TaskStandard {

    //确定任务单元
    Long taskUnit();

    //执行成功后更新日志记录的完成时间


}

TaskUtils

package com.sinoccdc.devops.scheduler.utils;

//import org.quartz.spi.TriggerFiredBundle;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonParser;
import com.sinoccdc.devops.utils.common.RedisUtil;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.stereotype.Component;
import springfox.documentation.spring.web.json.Json;

import javax.annotation.Resource;
import java.util.Map;

@Component
public  class TaskUtils {
	@Autowired
	private AutowireCapableBeanFactory capableBeanFactory;

	@Resource
	private RedisUtil redisUtil;

	//按照key向redis放数据
	public Boolean putDataToRedis(String JobCode, TaskRedisData taskRedisData){

		HashedMap<String, Object> map = new HashedMap<>();
		//完成百分比
		map.put("completePercent",taskRedisData.getCompletePercent());
		//完成时间
		map.put("completeTime",taskRedisData.getCompleteTime());
		//发生错误的标识
		map.put("failTag",taskRedisData.getFailTag());
		//其他信息
		map.put("message",taskRedisData.getMessage());

		return redisUtil.hmset(JobCode, map);

	}

	//按照key向redis拿数据
	public TaskRedisData getDataFromRedisByJobCode(String JobCode) {

		if (StringUtils.isEmpty(JobCode)) {
			throw new RuntimeException("JobCode不能为空");
		} else {
			if (redisUtil.get(JobCode) != null) {
				Object value = redisUtil.get(JobCode);

				TaskRedisData taskRedisData = (TaskRedisData) value;
				return taskRedisData;
			} else {
				return null;
			}

		}

	}

	//按照key向redis拿数据
	public Map<Object, Object> getMapByJobCode(String JobCode) {

		if(StringUtils.isEmpty(JobCode)){
			throw new RuntimeException("JobCode不能为空");
		}else{
			return redisUtil.hmget(JobCode);
		}

	}
}

配置文件quartz.properties

在这里插入图片描述

2.数据库设计

-- ----------------------------
-- Table structure for TC_SYS_TASK
-- ----------------------------
DROP TABLE "DEVOPS"."TC_SYS_TASK";
CREATE TABLE "DEVOPS"."TC_SYS_TASK" (
"ID" VARCHAR2(32 BYTE) NOT NULL ,
"PID" VARCHAR2(32 BYTE) NULL ,
"JOB_GROUP" VARCHAR2(100 BYTE) NULL ,
"JOB_CODE" VARCHAR2(100 BYTE) NULL ,
"JOB_NAME" VARCHAR2(255 BYTE) NULL ,
"DESCRIPTION" VARCHAR2(255 BYTE) NULL ,
"CRON_EXPRESSION" VARCHAR2(100 BYTE) NULL ,
"BEAN_CLASS" VARCHAR2(100 BYTE) NULL ,
"SERVICE_INTERFACE" VARCHAR2(300 BYTE) NULL ,
"SERVICE_INTERFACE_PARAMS" VARCHAR2(1000 BYTE) NULL ,
"JOB_STATUS" VARCHAR2(20 BYTE) NULL ,
"LAST_RUN_TIME" DATE NULL ,
"NEXT_RUN_TIME" DATE NULL ,
"CREATE_USER" VARCHAR2(100 BYTE) NULL ,
"CREATE_TIME" DATE NULL ,
"UPDATE_USER" VARCHAR2(100 BYTE) NULL ,
"UPDATE_TIME" DATE NULL ,
"REMARK" VARCHAR2(128 BYTE) NULL ,
"DELETE_FLAG" NUMBER(1) NULL ,
"ORDER_NUM" NUMBER(10) NULL 
)
LOGGING
NOCOMPRESS
NOCACHE

;
COMMENT ON TABLE "DEVOPS"."TC_SYS_TASK" IS '定时任务配置';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."ID" IS '主键';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."PID" IS '父任务ID';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."JOB_GROUP" IS '工作组';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."JOB_CODE" IS '任务编码';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."JOB_NAME" IS '任务名称';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."DESCRIPTION" IS '任务描述';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."CRON_EXPRESSION" IS 'cron表达式';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."BEAN_CLASS" IS '任务执行时调用哪个类的方法 包名+类名';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."SERVICE_INTERFACE" IS '服务接口';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."SERVICE_INTERFACE_PARAMS" IS '接口参数';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."JOB_STATUS" IS '工作状态';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."LAST_RUN_TIME" IS '上一次执行时间';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."NEXT_RUN_TIME" IS '预计下一次执行时间';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."CREATE_USER" IS '创建人';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."CREATE_TIME" IS '创建时间';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."UPDATE_USER" IS '更新人';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."UPDATE_TIME" IS '更新时间';
COMMENT ON COLUMN "DEVOPS"."TC_SYS_TASK"."DELETE_FLAG" IS '删除标记';

-- ----------------------------
-- Indexes structure for table TC_SYS_TASK
-- ----------------------------

-- ----------------------------
-- Uniques structure for table TC_SYS_TASK
-- ----------------------------
ALTER TABLE "DEVOPS"."TC_SYS_TASK" ADD UNIQUE ("JOB_GROUP", "JOB_CODE", "JOB_NAME");

-- ----------------------------
-- Checks structure for table TC_SYS_TASK
-- ----------------------------
ALTER TABLE "DEVOPS"."TC_SYS_TASK" ADD CHECK ("ID" IS NOT NULL);
ALTER TABLE "DEVOPS"."TC_SYS_TASK" ADD CHECK ("ID" IS NOT NULL);

-- ----------------------------
-- Primary Key structure for table TC_SYS_TASK
-- ----------------------------
ALTER TABLE "DEVOPS"."TC_SYS_TASK" ADD PRIMARY KEY ("ID");

3.ScheduleDistribute实现类

主要完成定时任务的具体实现,在此处为,从task表拿到任务实体具体内容并运行

package com.sinoccdc.devops.scheduler;

import com.sinoccdc.devops.domain.application.scheduler.SchedulerTaskLogService;
import com.sinoccdc.devops.domain.application.scheduler.SchedulerTaskService;
import com.sinoccdc.devops.portal.util.HttpUtil;
import com.sinoccdc.devops.web.page.scheduler.payload.SchedulerTaskLogPayload;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;

public class ScheduleDistribute implements Job {

    @Autowired
    private SchedulerTaskService schedulerTaskService;
    @Autowired
    private SchedulerTaskLogService schedulerTaskLogService;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobKey jd=context.getJobDetail().getKey();

        //根据找到task任务实体,找到要的参数
        SchedulerTask task = schedulerTaskService.findByJobGroupAndJobCode(jd.getGroup(), jd.getName());

        //生成日志记录
        SchedulerTaskLog taskLog = new SchedulerTaskLog();
        taskLog.setJobCode(task.getJobCode());
        taskLog.setJobGroup(task.getJobGroup());
        taskLog.setJobName(task.getJobName());
        taskLog.setTriggerMode(1);//自动
        taskLog.setStartTime(new Date());
        //集成http 的客户端,调用链接
        String serviceInterface = task.getServiceInterface();
        String params = task.getServiceInterfaceParams();
        //String request = HttpsUtils.httpsRequest(serviceInterface, "POST", params);

        //开启一个新线程去执行真正需要进行的任务
        Thread t = new Thread(new Runnable(){
            public void run(){
                // run方法具体重写
                //HttpUtil.sendPost(serviceInterface, params, false)
                HttpUtil.sendGet(serviceInterface+"/"+params);
            }});
        t.start();

        //完成

        schedulerTaskLogService.saveSchedulerTaskLog(taskLog);

    }
}

4.其他具体方法

比如从controller->service->dao->pojo的具体方法,都是围绕task表的增删查改

其中注意:

新增完task的数据后要把定时任务注册到quartz中去定时执行;

具体参照quartzManager中封装的各种方法

//开启定时任务
quartzManager.addJob(schedulerTask);
 //更新定时任务
quartzManager.updateJobCron(schedulerTask);
//删除定时任务
quartzManager.deleteJob(task);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值