JFinal Quartz 支持配置文件和持久化

Stella981
• 阅读 785

    随着需求的增加,现在要定时启动一个调度和计划任务,原先写的QuartzPlugin,是持久化保存到数据库中的,从数据库中读取任务并执行。要是添加一个每天循环任务,就要在代码里写一次开始任务的代码,执行后,再注释掉,最后重启项目。否则会因为启动同name,同group的任务而报错

org.quartz.ObjectAlreadyExistsException: Unable to store Job :
 'group_test_1.job_test_1', because one already exists with this identification.

    原先JFinal-ext中是通过配置文件,定时循环运行的,两者结合不就是我要的吗?

思路清晰,持久化依旧,再在QuartzPlugin 中增加读取配置文件后生成调度任务,当然,这个也会保存到数据库中的,所以还要在停止的时候,终止和删除相应调度任务,否则下次启动就会报冲突了。

修改的QuartzPlugin 依旧参考了jfinal-ext,做了一些修改,原先会依赖com.google.guava:guava这个jar,因为本人有点强迫症,不喜欢jar包太多,所以能不加就不加了。

import com.jfinal.plugin.IPlugin;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import sedion.net.gppz.quartz.QuartzFactory;
import sedion.net.gppz.utils.PropertiesUtil;

import java.util.*;

import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

/**
 * Quartz插件
 *
 * @author WWF
 */
public class QuartzPlugin implements IPlugin {

    private static final String JOB = "job";

    /**
     * 默认配置文件
     **/
    private String config = "quartz.properties";
    private String job_config = "jobs.properties";
    private Map<Job, String> jobs = new LinkedHashMap<>();
    private Map<String, String> jobProp;


    public QuartzPlugin() {

    }

    public QuartzPlugin(String config) {
        this.config = config;
    }

    public QuartzPlugin(String config, String job_config) {
        this.config = config;
        this.job_config = job_config;
    }

    @Override
    public boolean start() {
        try {
            //加载配置文件
            Properties props = PropertiesUtil.loadPropertyFile(config);
            //实例化
            QuartzFactory.sf = new StdSchedulerFactory(props);
            //获取Scheduler
            Scheduler sched = QuartzFactory.sf.getScheduler();

            //从配置文件中加载定时任务
            loadJobsFromProperties();
            if (jobs.size() > 0) {
                Set<Map.Entry<Job, String>> set = jobs.entrySet();
                for (Map.Entry<Job, String> entry : set) {
                    Job job = entry.getKey();
                    String jobClassName = job.getClass().getName();
                    String jobCronExp = entry.getValue();
                    JobDetail jobDetail = newJob(job.getClass())
                            .withIdentity(jobClassName, jobClassName)
                            .requestRecovery()
                            .build();
                    CronTrigger trigger = newTrigger()
                            .withIdentity(jobClassName, jobClassName)
                            .withSchedule(CronScheduleBuilder.cronSchedule(jobCronExp))
                            .build();
                    sched.scheduleJob(jobDetail, trigger);
                }
            }
            sched.start();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean stop() {
        try {
            //从配置文件中加载定时任务
            loadJobsFromProperties();
            Scheduler sched = QuartzFactory.sf.getScheduler();
            if (jobs.size() > 0) {
                Set<Map.Entry<Job, String>> set = jobs.entrySet();
                for (Map.Entry<Job, String> entry : set) {
                    Job job = entry.getKey();
                    String jobClassName = job.getClass().getName();
                    TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobClassName);
                    Trigger trigger = sched.getTrigger(triggerKey);
                    if (trigger != null) {
                        sched.pauseTrigger(triggerKey);// 停止触发器
                        sched.unscheduleJob(triggerKey);// 移除触发器
                        sched.deleteJob(trigger.getJobKey());// 删除任务
                    }
                }
            }
            sched.shutdown();
            QuartzFactory.sf = null;
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 从配置文件中加载定时任务
     */
    private void loadJobsFromProperties() {
        //清空任务
        jobs.clear();
        Properties properties = PropertiesUtil.loadPropertyFile(job_config);
        jobProp = new HashMap<>((Map) properties);
        Set<Map.Entry<String, String>> entries = jobProp.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            if (!key.endsWith(JOB) || !isEnableJob(key)) {
                continue;
            }
            String jobClassName = jobProp.get(key) + "";
            String jobCronExp = jobProp.get(cronKey(key)) + "";
            try {
                Class c = Class.forName(jobClassName);
                jobs.put((Job) c.newInstance(), jobCronExp);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获得cron表达式
     * @param key
     * @return
     */
    private String cronKey(String key) {
        return key.substring(0, key.lastIndexOf(".") + 1) + "cron";
    }

    /**
     * 是否开启
     * @param key
     * @return
     */
    private boolean isEnableJob(String key) {
        String enableKey = key.substring(0, key.indexOf(".") + 1) + "enable";
        Object enable = jobProp.get(enableKey);
        if (enable != null && "true".equalsIgnoreCase((enable + "").trim())) {
            return true;
        }
        return false;
    }

}

    在看jfinal-ext源码的时候,有个疑问,

    看介绍,job的配置文件是

#JobA
a.job=test.com.jfinal.plugin.quzrtz.JobA
a.cron=*/5 * * * * ?
a.enable=true

    但是在代码中,转化为map后,获取相应的key的处理是

private String enable(String key) {
    return key.substring(0, key.lastIndexOf(JOB)) + "enable";
}

private String cronKey(String key) {
    return key.substring(0, key.lastIndexOf(JOB)) + "cron";
}

      所以我觉得配置文件应该是

#JobA
a.job=test.com.jfinal.plugin.quzrtz.JobA
a.job.cron=*/5 * * * * ?
a.job.enable=true

或者是获得key的截取改一下

再次感谢jfinal 和jfinal-ext。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这