Spring+Quartz实现动态添加定时任务

本文介绍了如何结合Spring和Quartz实现在数据库中动态添加和管理定时任务。内容包括环境准备、代码结构、数据库配置、项目启动与交互、代码实现细节,以及提供了详细的代码下载链接和操作说明。
摘要由CSDN通过智能技术生成
发布时间:2018-12-03
 
技术:spring4.0.2+quartz2.2.1
 

概述

在最近工作中,由于涉及到定时任务特别多,而这些工作又是由下属去完成的,在生成环境中经常会出现业务逻辑错误,分析下来多数是定时任务运行问题,所以就希望把定时任务优化一下,主要实现2个方面 1.定时任务动态配置及持久化 2.可视化的管理界面,可以非常清晰的管理自己的所有定时任务 源码是我重新梳理后的(陆陆续续花了我好几天晚上),整个框架去除了多余的内容,仅保留quartz及springAop,能非常好的解决业务中的定时任务,而且还能所见即所得的知道目前有哪些任务在跑,对任务具体执行的情况进行日志分析;框架采用ssm搭建,结合自己工作中框架的结构问题做了优化,如果对这个单体架构感兴趣,底层可以在platform_parent中扩展,应用层可在cloud_parent中进行扩展

详细

一、准备工作

1.java环境搭建,具体参考包中的webapp/resources/doc/平台开发环境安装Guide_V1.0.docx文档

image.png

2.使用源码中的webapp/resources/doc/init.sql初始化表结构及数据

t_timetask 任务表

t_timetask_log 任务运行日志

3.数据库连接配置在cloud_parent中的pom.xml中,数据库名称ffxl_cloud,默认账号root,密码123456,同样可在pom.xml中修改

4.运行quartz项目,此处注意,使用的端口号需要与platform_parent下pom.xml中的quartz.job.url的一致,程序中用的是8080端口,具体使用哪个配置,请参考maven中profiles的使用

5.运行admin项目,注意,此处端口要与quartz不同,程序中用的是80端口,浏览器中输入http://localhost/admin 运行结果如图:

image.png

二、代码引入

1、文件引入顺序:lib_parent → platform_parent → cloud_parent

2、代码结构

image.png

三、程序实现

quartz项目部分代码

1.quartz项目启动时,初始化数据库中的定时任务

package com.ffxl.quartz.init;

import java.util.ArrayList;
import java.util.List;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import com.ffxl.cloud.model.STimetask;
import com.ffxl.cloud.model.STimetaskExample;
import com.ffxl.cloud.model.base.BaseSTimetaskExample.Criteria;
import com.ffxl.cloud.model.warpper.ScheduleJob;
import com.ffxl.cloud.service.STimetaskService;
import com.ffxl.quartz.task.util.QuartzJobFactory;
import com.ffxl.quartz.task.util.QuartzJobFactoryDisallowConcurrentExecution;


/**
 * 根据上下文获取spring类
 * 
 * @author
 */
public class InitQuartzJob implements ApplicationContextAware{
  private static final Logger logger = LoggerFactory.getLogger(InitQuartzJob.class);
  
  private static ApplicationContext appCtx;
  public static SchedulerFactoryBean schedulerFactoryBean = null;


  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    if (this.appCtx == null) {
      this.appCtx = applicationContext;
    }
  }
  
  public static void init() {
    schedulerFactoryBean = (SchedulerFactoryBean) appCtx.getBean(SchedulerFactoryBean.class);
    Scheduler scheduler = schedulerFactoryBean.getScheduler();
    try {
      logger.info(scheduler.getSchedulerName());
    } catch (SchedulerException e1) {
      // TODO Auto-generated catch block
      e1.printStackTrace();
    }
    // 这里从数据库中获取任务信息数据
    STimetaskService sTimetaskService = (STimetaskService) appCtx.getBean(STimetaskService.class);
    STimetaskExample example = new STimetaskExample();
    Criteria c = example.createCriteria();
    c.andJobStatusEqualTo("1"); // 已发布的定时任务
    List<STimetask> list = sTimetaskService.selectByExample(example);
    List<ScheduleJob> jobList = new ArrayList<ScheduleJob>();
    for (STimetask sTimetask : list) {
      ScheduleJob job1 = new ScheduleJob();
      job1.setJobId(sTimetask.getId());
      job1.setJobGroup(sTimetask.getGroupName()); // 任务组
      job1.setJobName(sTimetask.getName());// 任务名称
      job1.setJobStatus(sTimetask.getJobStatus()); // 任务发布状态
      job1.setIsConcurrent(sTimetask.getConcurrent() ? "1" : "0"); // 运行状态
      job1.setCronExpression(sTimetask.getCron());
      job1.setBeanClass(sTimetask.getBeanName());// 一个以所给名字注册的bean的实例
      job1.setMethodName(sTimetask.getMethodName());
      job1.setJobData(sTimetask.getJobData()); // 参数
      jobList.add(job1);
    }

    for (ScheduleJob job : jobList) {
      try {
        addJob(job);
      } catch (SchedulerException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }

  /**
   * 添加任务
   * 
   * @param scheduleJob
   * @throws SchedulerException
   */
  public static void addJob(ScheduleJob job) throws SchedulerException {
    if (job == null || !ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) {
      return;
    }

    Scheduler scheduler = schedulerFactoryBean.getScheduler();
    logger.debug(scheduler + "...........................................add");
    TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());

    CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

    // 不存在,创建一个
    if (null == trigger) {
      Class clazz = ScheduleJob.CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class
                                                                           : QuartzJobFactoryDisallowConcurrentExecution.class;

      JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).usingJobData("data", job.getJobData()).build();

      jobDetail.getJobDataMap().put("scheduleJob", job);

      CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

      trigger = TriggerBuilder.newTrigger().withDescription(job.getJobId().toString()).withIdentity(job.getJobName(), job.getJobGroup())
          .withSchedule(scheduleBuilder).build();

      scheduler.scheduleJob(jobDetail, trigger);
    } else {
      // Trigger已存在,那么更新相应的定时设置
      CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

      // 按新的cronExpression表达式重新构建trigger
      trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).usingJobData("data", job.getJobData()).withSchedule(scheduleBuilder).build();

      // 按新的trigger重新设置job执行
      scheduler.rescheduleJob(triggerKey, trigger);
    }
  }

}

 

2.提供job对应的操作服务

package com.ffxl.quartz.task;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;

import org.apache.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSONObject;
import com.ffxl.cloud.annotation.ControllerLogAnnotation;
import com.ffxl.cloud.model.STimetask;
import com.ffxl.cloud.model.warpper.ScheduleJob;
import com.ffxl.platform.util.JsonResult;
import com.ffxl.platform.util.StringUtil;
import com.ffxl.quartz.init.InitQuartzJob;

@Component
@RequestMapping(value = "/opt")
public class JobSerlvet {
  public final Logger log = Logger.getLogger(this.getClass());

  @Autowired
  private SchedulerFactoryBean schedulerFactoryBean;

  /**
   * 获取所有计划中的任务列表
   * 
   * @return
   * @throws SchedulerException
   * @thr
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值