springboot 自定义定时任务

本文介绍了如何使用Spring Boot和Quartz框架设计一个可管理的自定义定时任务系统,包括任务的创建、保存、启动、停止和状态控制,以及通过REST API进行操作。详细涵盖了任务实体的定义、控制层、业务层和DAO层的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 使用ScheduledFuture 自定义定时任务。
2 通过持久化定时任务,任务包括任务名称,描述,规则,状态,制定任务执行的具体线程,参数等,通过rest风格接口调用来crud任务 ,启动任务,停止任务。
3 任务线程类中处理具体的业务。

  1. 自定义任务实体类
@Entity
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ScheduleTask {

    /**
     * Id
     */
    @Id
    @GeneratedValue(generator = "idGenerator")
    @GenericGenerator(name ="idGenerator" ,strategy="org.common.ids.SerialIdGeneratorSnowflakeId")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long id;

    /**
     * 任务名称
     */
    @Column(name = "NAME")
    @ApiModelProperty("任务名称")
    private String name;

    @Column(name = "DESC_TXT",columnDefinition = "text")
    @ApiModelProperty("任务描述")
    private String descTxt;

    /**
     * 任务描述
     */
    @Column(name = "CRON")
    @ApiModelProperty("任务cron @Schedule 规则")
    private String cron;

    /**
     * 任务状态
     */
    @Column(name = "STATUS")
    @Enumerated(EnumType.STRING)
    @ApiModelProperty("任务状态")
    private Status status;

    /**
     * 开关
     */
    @Column(name = "deleted")
    @ApiModelProperty("是否删除")
    private Boolean deleted = false;

    /**
     * 执行指定类
     * 指定具体的包名
     */
    @Column(name = "EXE_CLASS")
    @ApiModelProperty("执行指定类 com.test.autojob.xxxRunnable")
    private String exeClass;

    /**
     * 任务参数 json
     */
    @Column(name = "PARAMS")
    @ApiModelProperty("任务参数")
    private String params;

    @Column(name = "CREATE_TIME")
    private LocalDateTime createTime;

    @Column(name = "UPDATE_TIME")
    private LocalDateTime updateTime;


    public enum Status{
        create,
        running,
        stop
    }

}

在这里插入图片描述

  1. 自定义任务控制层
/**
 * 自定义定时任务
 * @author zhangwx
 * @date 2022/07/22 14:05
 */
@RestController
@Api(tags = "自定义定时任务")
public class ScheduleTaskController  {

    private ScheduleTaskService scheduleTaskService;

    public ScheduleTaskController(ScheduleTaskService scheduleTaskService) {
        this.scheduleTaskService = scheduleTaskService;
    }

    @PostConstruct
    public void init(){
        scheduleTaskService.startAll();
    }

    /**
     * 保存
     * @param scheduleTask
     * @return
     */
    @PostMapping("/save")
    @ApiOperation("新增或保存自定义任务")
    public ReturnData<ScheduleTask> save(@RequestBody ScheduleTask scheduleTask){
        try {
            ScheduleTask task= scheduleTaskService.save(scheduleTask);
            return new ReturnData<>(ReturnData.SUCCESS_CODE,"保存成功",task,null);
        } catch (Exception e) {
            e.printStackTrace();
            return new ReturnData<>(ReturnData.FAIL_CODE,"保存失败"+e.getMessage(),null,null);
        }
    }

    /**
     * 启动
     * @param taskId
     * @return
     */
    @GetMapping("/start/{taskId}")
    @ApiOperation("启动任务")
    public ReturnData<String> start(@PathVariable(value = "taskId") Long taskId){
        try {
            scheduleTaskService.start(taskId);
            return new ReturnData<>(ReturnData.SUCCESS_CODE,"启动成功",null,null);
        } catch (Exception e) {
            e.printStackTrace();
            return new ReturnData<>(ReturnData.FAIL_CODE,"启动失败"+e.getMessage(),null,null);
        }
    }

    /**
     * 重启
     * @param taskId
     * @return
     */
    @GetMapping("/restart/{taskId}")
    @ApiOperation("重启")
    public ReturnData<String> restart(@PathVariable(value = "taskId") Long taskId){
        try {
            scheduleTaskService.restart(taskId);
            return new ReturnData<>(ReturnData.SUCCESS_CODE,"重启成功",null,null);
        } catch (Exception e) {
            e.printStackTrace();
            return new ReturnData<>(ReturnData.FAIL_CODE,"重启失败"+e.getMessage(),null,null);
        }
    }

    /**
     * 停止任务
     * @param taskId
     * @return
     */
    @GetMapping("/stop/{taskId}")
    @ApiOperation("停止任务")
    public ReturnData<String> stop(@PathVariable(value = "taskId") Long taskId){
        try {
            scheduleTaskService.stop(taskId);
            return new ReturnData<>(ReturnData.SUCCESS_CODE,"停止成功",null,null);
        } catch (Exception e) {
            e.printStackTrace();
            return new ReturnData<>(ReturnData.FAIL_CODE,"停止失败"+e.getMessage(),null,null);
        }
    }
}
  1. 自定义任务业务层
/**
 * @author zhangwx
 * @date 2022/07/22 13:52
 */
@Service
public class ScheduleTaskServiceImpl  implements ScheduleTaskService {

    private ScheduleTaskDao scheduleTaskDao;
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    private ApplicationContext applicationContext;
    /**
     * 正在运行的任务
     */
    public static ConcurrentHashMap<Long,ScheduledFuture> runTasKMap = new ConcurrentHashMap<>();



    public ScheduleTaskServiceImpl(ScheduleTaskDao scheduleTaskDao,
                                   ThreadPoolTaskScheduler threadPoolTaskScheduler,
                                   ApplicationContext applicationContext) {
        this.scheduleTaskDao = scheduleTaskDao;
        this.threadPoolTaskScheduler = threadPoolTaskScheduler;
        this.applicationContext = applicationContext;
    }

    @Override
    public List<ScheduleTask> findAllTasks() {
        return scheduleTaskDao.findAllByDeleted(false);
    }

    @Override
    public ReturnData<String> startAll() {
        List<ScheduleTask> allTasks = findAllTasks();
        for (ScheduleTask task : allTasks) {
            if (runTasKMap.containsKey(task.getId())){
                continue;
            }
            try {
                this.start(task.getId());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        return new ReturnData<>(ReturnData.SUCCESS_CODE,"所有任务启动成功",null,null);
    }

    @Override
    public ScheduleTask save(ScheduleTask scheduleTask) {
        return scheduleTaskDao.saveAndFlush(scheduleTask);
    }

    @Override
    public ReturnData<String> start(Long taskId) throws Exception{
        ScheduleTask scheduleTask = scheduleTaskDao.findById(taskId).orElse(null);
        this.assertTaskNotRunning(scheduleTask);
        Runnable runnable = getTaskRunnable(scheduleTask);
        CronTrigger trigger = new CronTrigger(scheduleTask.getCron());
        ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(runnable, trigger);
        assert future != null;
        runTasKMap.put(taskId,future);

        this.updateTaskStatus(scheduleTask,ScheduleTask.Status.running);

        return new ReturnData<>(ReturnData.SUCCESS_CODE,"启动成功",null,null);
    }

    private JobRunnables getTaskRunnable(ScheduleTask scheduleTask) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Class<?> aClass = Class.forName(scheduleTask.getExeClass());
        //创建job对象
        Constructor<?> constructor = aClass.getConstructor(String.class,ApplicationContext.class);
        return (JobRunnables) constructor.newInstance(scheduleTask.getParams(),applicationContext);
    }


    @Override
    public ReturnData<String> restart(Long taskId) throws Exception{
        stop(taskId);
        start(taskId);
        return new ReturnData<>(ReturnData.SUCCESS_CODE,"任务重启成功",null,null);
    }

    @Override
    public ReturnData<String> stop(Long taskId) throws Exception{
        ScheduledFuture scheduledFuture = runTasKMap.get(taskId);
        if (null == scheduledFuture){
            return new ReturnData<>(ReturnData.FAIL_CODE,"没有执行中的任务",null,null);
        }
        boolean cancel = scheduledFuture.cancel(true);
        if (cancel){
            runTasKMap.remove(taskId);
        }

        updateTaskStatus(scheduleTaskDao.findById(taskId).orElse(null), ScheduleTask.Status.stop);

        return new ReturnData<>(ReturnData.SUCCESS_CODE,"任务停止成功",null,null);
    }



    private void updateTaskStatus(ScheduleTask scheduleTask, ScheduleTask.Status status) {
        if (null == scheduleTask){
            return;
        }
        scheduleTask.setStatus(status);
        scheduleTask.setUpdateTime(LocalDateTime.now());
        scheduleTaskDao.save(scheduleTask);
    }

    private void assertTaskNotRunning(ScheduleTask scheduleTask) throws ScheduleTaskException {
        if (null == scheduleTask){
            throw new ScheduleTaskException("查询不到任务");
        }
        ScheduledFuture scheduledFuture = runTasKMap.get(scheduleTask.getId());
        if (null != scheduledFuture){
            throw new ScheduleTaskException("任务正在运行中");
        }
//        if (ScheduleTask.Status.running.equals(scheduleTask.getStatus())){
//            throw new ScheduleTaskException("任务正在运行中");
//        }
    }

}

  1. 自定义任务dao层
public interface ScheduleTaskDao extends JpaRepository<ScheduleTask,Long>, JpaSpecificationExecutor<ScheduleTask> {

    List<ScheduleTask> findAllByDeleted(Boolean deleted);
}

  1. 自定义任务
/**	
 * @author zhangwx 抽象的业务任务执行线程
 * @date 2022/07/22 16:38
 */
public abstract class JobRunnables implements Runnable {

    private String params;
    private ApplicationContext applicationContext;

    public JobRunnables(String params, ApplicationContext applicationContext) {
        this.params = params;
        this.applicationContext = applicationContext;
    }

    public String getParams() {
        return params;
    }

    public void setParams(String params) {
        this.params = params;
    }

    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}
/**
 * 具体的业务job
 * @author zhangwx
 * @date 2022/07/22 16:42
 */
@Slf4j
public class AutoWithdrawalRunnable extends JobRunnables {

    private final TestFeign testFeign;
    private final MerchantCacheService merchantCacheService;

    public AutoWithdrawalRunnable(String params, ApplicationContext applicationContext) {
        super(params, applicationContext);
        FeignContext feignContext = applicationContext.getBean("feignContext", FeignContext.class);
        merchantCacheService = applicationContext.getBean("merchantCacheServiceImpl",MerchantCacheService.class);
        testFeign = feignContext.getInstance("testFeign", TestFeign.class);
    }

    @Override
    public void run() {
        try {
            String param= getParams();
            //todo 具体业务实现类
        } catch (Exception e) {
            log.error("自动提现异常,msg:"+e.getMessage(),e);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值