基于quartz的动态任务

quartz是一个提供定时任务的框架。任务可以直接配置在配置文件之中或者数据库里,这种无法修改的任务可以叫做静态任务,而这次写的是怎么创建动态任务,可以在项目运行中对定时任务进行创建、修改、删除等操作。
我这里是基于spring框架搭建的quartz系统。spring配置文件中配置了SchedulerFactoryBean工厂类,用于生成Scheduler对象。

<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
        <property name="dataSource"><!--数据库数据源,这里的任务是配置在数据库中的-->
            <ref bean="qrtzDataSource"/>
        </property>
        <property name="autoStartup" value="true"/> <!--开发人员本机此处默认为false-->
        <property name="startupDelay" value="60" />
        <property name="applicationContextSchedulerContextKey" value="applicationContext"/>
        <property name="configLocation" value="classpath:/spring/quartz.properties"/>
    </bean>

表结构都是quartz项目提供的,我用的mysql,选取对应文件即可。
这里写图片描述

开始coding
1、首先定义一个我们需要的job的信息类

public class QuartzJobBean implements Serializable {
    private static final long serialVersionUID = 8426499555496553217L;

    public static final String CONCURRENT_IS = "1";

    public static final String CONCURRENT_NOT = "0";

    public static final String STATUS_NONE = "NONE";

    public static final String STATUS_NORMAL = "NORMAL";

    public static final String STATUS_PAUSED = "PAUSED";

    public static final String STATUS_COMPLETE = "COMPLETE";

    public static final String STATUS_ERROR = "ERROR";

    public static final String STATUS_BLOCKED = "BLOCKED";

    /** 任务id */
    private String jobId;

    /** 任务名称 */
    private String jobName;

    /** 任务分组,任务名称+组名称应该是唯一的 */
    private String jobGroup;

    /** 任务初始状态 0禁用 1启用 2删除*/
    private String jobStatus;

    /** 任务是否有状态(并发) */
    private String isConcurrent = "1";

    /** 任务运行时间表达式 */
    private String cronExpression;

    /** 任务描述 */
    private String description;

    /** 任务调用类在spring中注册的bean id,如果spingId不为空,则按springId查找 */
    private String springId;

    /** 任务调用类名,包名+类名,通过类反射调用 ,如果spingId为空,则按jobClass查找   */
    private String jobClass;

    /** 任务调用的方法名 */
    private String methodName;

    /** 启动时间 */
    private Date startTime;

    /** 前一次运行时间 */
    private Date previousTime;

    /** 下次运行时间 */
    private Date nextTime;

//getter、setter方法

2、接下来是核心任务操作类

@Component
public class QuartzJobManage {
    private static final Logger logger = LoggerFactory.getLogger(QuartzJobManage.class);

    /**
     * 添加任务
     *
     * @param scheduleJob
     */
    public void addJob(QuartzJobBean scheduleJob) throws CustomerBizException {
        try {
            if (scheduleJob == null || !QuartzJobBean.STATUS_NORMAL.equals(scheduleJob.getJobStatus()))
                throw new CustomerBizException("添加的任务不能为null并且任务的初始状态必须是[STATUS_NORMAL]");
            if (!TaskUtils.isValidExpression(scheduleJob.getCronExpression()))
                throw new CustomerBizException("任务名称[" + scheduleJob.getJobName() + "] 任务分组[" + scheduleJob.getJobGroup() + "]的时间表达式错误:" + scheduleJob.getCronExpression());
            //SpringContextUtil.getBean("schedulerFactoryBean");就是封装的这个applicationContext.getBean(name);这句代码里面有关于spring IOC的一个机制,如果你实现了spring的FactoryBean<T>接口,那你通过applicationContext.getBean(name)返回的将是getObjectType()方法返回的对象,类型为T,详情可参见spring源码
            Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
            final TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
            Trigger trigger = scheduler.getTrigger(triggerKey);
            if (null == trigger){
            //这是QuartzJobBean类中定义的真正要执行的任务类
                Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(scheduleJob.getJobClass());
                final JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).build();
                jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
                final CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
                trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                scheduler.scheduleJob(jobDetail, trigger);
            } else {
                // trigger已存在,则更新相应的定时设置
                final CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
                trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

/** 暂停任务
     * @param scheduleJob
     * @return
     */
    public void pauseJob(QuartzJobBean scheduleJob){
        try {
            Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
            final JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            logger.error("任务暂停失败:", e);
        }
    }

    /**
     * 恢复任务
     * @param scheduleJob
     * @return
     */
    public void resumeJob(QuartzJobBean scheduleJob) {
        try {
            Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
            final JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            logger.error("任务恢复失败:", e);
        }
    }

    /**
     * 删除任务
     */
    public void deleteJob(QuartzJobBean scheduleJob){
        try {
            Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
            final JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
            scheduler.deleteJob(jobKey);
        } catch (SchedulerException e) {
            logger.error("任务名称[" + scheduleJob.getJobName() + "] 分组[" + scheduleJob.getJobGroup() + "] 删除失败!", e);
        }
    }

/**
     * 获取单个任务
     * @param jobName
     * @param jobGroup
     * @return
     * @throws SchedulerException
     */
    public QuartzJobBean findJob(String jobName, String jobGroup)
    {
        try
        {
            QuartzJobBean job = null;
            Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            CronTrigger trigger = (CronTrigger)scheduler.getTrigger(triggerKey);

            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);

            if (trigger != null && jobDetail != null)
            {
                QuartzJobBean jobExist = (QuartzJobBean)jobDetail.getJobDataMap().get("scheduleJob");
                job = new QuartzJobBean();
                job.setJobName(jobName);
                job.setJobGroup(jobGroup);
                job.setDescription("触发器:" + trigger.getKey());
                job.setNextTime(trigger.getNextFireTime()); //下次触发时间
                job.setPreviousTime(trigger.getPreviousFireTime());//上次触发时间
                job.setDescription(jobExist.getDescription());
                job.setJobClass(jobExist.getJobClass());
                job.setMethodName(jobExist.getMethodName());

                Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
                job.setJobStatus(triggerState.name());
                if (trigger instanceof CronTrigger)
                {
                    CronTrigger cronTrigger = (CronTrigger)trigger;
                    String cronExpression = cronTrigger.getCronExpression();
                    job.setCronExpression(cronExpression);
                }
            }
            return job;
        }
        catch (Exception e)
        {
            logger.error("任务获取失败:", e);
        }
        return null;
    }
    }

3、任务执行我用的quartz的Job类,通过集成spring的QuartzJobBean类,他是一个实现了Job接口,完成了任务执行模板(模板模式)的抽象类,我们继承他实现一些自己的逻辑和规则。BaseJob 类也是一个模板,run()方法的实现就是要执行的任务。

@Component
public abstract class BaseJob extends QuartzJobBean{

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

    /**
     * 供实现类运行
     * @param context 任务执行上下文
     * @throws JobExecutionException 任务执行时异常
     */
    protected abstract void run(JobExecutionContext context) throws JobExecutionException;

    /**
     * @param context 任务执行上下文
     * @throws JobExecutionException 任务执行时异常
     */
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        try {
            run(context);
        }
        catch (Exception e) {
            logger.error(e.toString());
        }
        finally {

        }
    }
}

4、任务实现类,举例

public class OrderPayTask extends BaseJob {
    @Override
    protected void run(JobExecutionContext context) throws JobExecutionException {
    //自己的任务实现
    }
    }

5、任务工具类

public class TaskUtils {
    private static final Logger logger = LoggerFactory.getLogger(TaskUtils.class);
/**
     * 判断cron时间表达式正确性
     * @param cronExpression
     * @return
     */
    public static boolean isValidExpression(String cronExpression){
        CronTriggerImpl trigger = new CronTriggerImpl();
        try {
            trigger.setCronExpression(cronExpression);
            final Date date = trigger.computeFirstFireTime(null);
            return date != null && date.after(new Date());
        } catch (ParseException e) {
            logger.error("时间表达式:" + cronExpression + "错误");
        }
        return false;
    }
    }

6、成功之后主要表里的数据
qrtz_job_details这里写图片描述
qrtz_job_details
这里写图片描述
qrtz_triggers
这里写图片描述

就此完结!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值