jfinal定时调度任务插件QuartzPlugin

jfinal与quartz结合。

即可以在配置文件中配置定时任务。又可动态添加新的定时任务。

使用中的项目:

http://www.3dmomoda.com

依赖jar包:quartz-2.0.2.jar

其他的依赖自己稍微改下就可以


quartz_config.properties(quartz配置)

#============================================================================
# 配置主要调度程序属性
#============================================================================
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false

#============================================================================
# 配置线程池  
#============================================================================
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5

#============================================================================
# 配置任务 
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000

org.quartz.scheduler.skipUpdateCheck = true

quartz_job.properties(任务配置,默认的调度任务可以在这里添加)

#开启的任务列表“,”隔开
jobArray = task1,task2

#搭客任务定时结束
task1.job=com.momoda.quartz.Task1
task1.cron=00 00 23 * * ?
task1.desc=任务1

#归档登录日志
task2.job=com.momoda.quartz.Task2
task2.cron=00 00 04 * * ?
task2.desc=任务2

FormaterCronExpression.java(日期转cron定时表达式类)

public class FormaterCronExpression {
	static String formart = "yyyy-MM-dd HH:mm:ss";

	public static String formaterCronExpression(String date) {
		SimpleDateFormat format = new SimpleDateFormat(formart.substring(0, date.length() - 1));
		SimpleDateFormat format2 = new SimpleDateFormat("yyyy MM dd HH mm ss");
		try {
			Date d = format.parse(date);
			date = format2.format(d);
			String[] dateArry = date.split(" ");
			String exp = dateArry[5] + " " + dateArry[4] + " " + dateArry[3] + " " + dateArry[2] + " " + dateArry[1]
					+ " ? " + dateArry[0];
			return exp;
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "";
	}

}

JobBean.java(任务对象实体bean)

/**
 * 计划任务信息
 */
public class JobBean {

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

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

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

	/** 任务分组 */
	private String jobGroup;

	/** 任务类 */
	private String jobClass;

	public String getJobId() {
		return jobId;
	}

	public void setJobId(String jobId) {
		this.jobId = jobId;
	}

	public String getJobDesc() {
		return jobDesc;
	}

	public void setJobDesc(String jobDesc) {
		this.jobDesc = jobDesc;
	}

	public String getCronExpression() {
		return cronExpression;
	}

	public void setCronExpression(String cronExpression) {
		this.cronExpression = cronExpression;
	}

	public String getJobGroup() {
		return jobGroup;
	}

	public void setJobGroup(String jobGroup) {
		this.jobGroup = jobGroup;
	}

	public String getJobClass() {
		return jobClass;
	}

	public void setJobClass(String jobClass) {
		this.jobClass = jobClass;
	}

	public JobBean(String jobId, String jobDesc, String cronExpression, String jobGroup, String jobClass) {
		this.jobId = jobId;
		this.jobDesc = jobDesc;
		this.cronExpression = cronExpression;
		this.jobGroup = jobGroup;
		this.jobClass = jobClass;
	}

	public JobBean() {
		super();
	}
}

QuartzPlugin.java(插件类)

public class QuartzPlugin implements IPlugin {
	private List<JobBean> jobs = new ArrayList<JobBean>();
	private SchedulerFactory sf;
	private static Scheduler scheduler;
	private String jobConfig;
	private String confConfig;
	private Map<String, String> jobProp;

	public QuartzPlugin(String jobConfig, String confConfig) {
		this.jobConfig = jobConfig;
		this.confConfig = confConfig;
	}

	public QuartzPlugin(String jobConfig) {
		this.jobConfig = jobConfig;
		this.confConfig = "/quartz_config.properties";
	}

	public QuartzPlugin() {
		this.jobConfig = "/quartz_job.properties";
		this.confConfig = "/quartz_config.properties";
	}

	public static void addJob(JobBean job) {
		try {
			TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobDesc(), job.getJobGroup());
			CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
			// 不存在,创建一个
			if (null == trigger) {
				Class<Job> j2 = (Class<Job>) Class.forName(job.getJobClass());
				JobDetail jobDetail = JobBuilder.newJob(j2).withIdentity(job.getJobDesc(), job.getJobGroup()).build();
				jobDetail.getJobDataMap().put("scheduleJob", job);

				// 表达式调度构建器
				CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

				// 按新的cronExpression表达式构建一个新的trigger
				trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobDesc(), job.getJobGroup())
						.withSchedule(scheduleBuilder).build();
				try {
					scheduler.scheduleJob(jobDetail, trigger);
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else {
				// Trigger已存在,那么更新相应的定时设置
				// 表达式调度构建器
				CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

				// 按新的cronExpression表达式重新构建trigger
				trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

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

	@Override
	public boolean start() {
		loadJobsFromProperties();
		startJobs();
		return true;
	}

	private void startJobs() {
		try {
			if (StrKit.notBlank(confConfig)) {
				sf = new StdSchedulerFactory(confConfig);
			} else {
				sf = new StdSchedulerFactory();
			}
			scheduler = sf.getScheduler();
		} catch (SchedulerException e) {
			Throwables.propagate(e);
		}
		for (JobBean entry : jobs) {
			addJob(entry);
		}
		try {
			scheduler.start();
		} catch (SchedulerException e) {
			Throwables.propagate(e);
		}
	}

	private void loadJobsFromProperties() {
		if (StrKit.isBlank(jobConfig)) {
			return;
		}
		jobProp = ResourceKit.readProperties(jobConfig);
		String jobArray = jobProp.get("jobArray");
		if (StrKit.isBlank(jobArray)) {
			return;
		}
		String[] jobArrayList = jobArray.split(",");
		for (String jobName : jobArrayList) {
			jobs.add(createJobBean(jobName));
		}
	}

	private JobBean createJobBean(String key) {
		JobBean job = new JobBean();
		job.setJobClass(jobProp.get(key + ".job"));
		job.setCronExpression(jobProp.get(key + ".cron"));
		job.setJobGroup(jobProp.get(key));
		job.setJobDesc(jobProp.get(key + ".desc"));
		return job;
	}

	@Override
	public boolean stop() {
		try {
			scheduler.shutdown();
		} catch (SchedulerException e) {
			Throwables.propagate(e);
		}
		return true;
	}
}


configPlugin方法中将插件启动就可以


动态添加定时任务

JobBean job = new JobBean();
job.setJobClass("com.momoda.quartz.DakeTaskJob");
job.setCronExpression(FormaterCronExpression.formaterCronExpression(task.getStr("closingTime")));
job.setJobGroup("DakeTaskJob");
job.setJobDesc("DakeTaskJob_" + taskid);
QuartzPlugin.addJob(job);


评论区

jianghe727

2019-06-01 16:03

@JFinal 你好,quartz的Job监听也可以通过这种方式添加吗?

JFinal

2019-06-01 16:40

@jianghe727 我前面提到的监听是指 java web 标准组件中的 Listener,如果你谈到的 quartz 的 job 监听是基于 java web 标准组件 Listener 实现的,那是可以的

WJME

2020-03-15 15:29

任务死活不执行,找了半天没找到原因,求助大佬 @JFinal @埋头苦干


====================== QuartzPlugin =====================

package com.wjme.app.job.plugin;

import com.jfinal.kit.LogKit;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.IPlugin;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

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

public class QuartzPlugin implements IPlugin {
private List jobs = new ArrayList();
private SchedulerFactory sf;
public static Scheduler scheduler;
private String jobConfig;
private String confConfig;
private Properties jobProp;

public QuartzPlugin(String jobConfig, String confConfig) {
this.jobConfig = jobConfig;
this.confConfig = confConfig;
}

public QuartzPlugin(String jobConfig) {
this.jobConfig = jobConfig;
this.confConfig = "quartz.properties";
}

public QuartzPlugin() {
this.jobConfig = "quartz.properties";
this.confConfig = "quartz.properties";
}

public static void addJob(JobBean job) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobDesc(), job.getJobGroup());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 不存在,创建一个
if (null == trigger) {
Class j2 = (Class) Class.forName(job.getJobClass());
JobDetail jobDetail = JobBuilder.newJob(j2).withIdentity(job.getJobDesc(), job.getJobGroup()).build();
jobDetail.getJobDataMap().put("scheduleJob", job);

// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

// 按新的cronExpression表达式构建一个新的trigger
trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobDesc(), job.getJobGroup())
.withSchedule(scheduleBuilder).build();
try {
scheduler.scheduleJob(jobDetail, trigger);
} catch (Exception e) {
e.printStackTrace();
LogKit.error("", e);
}
} else {
// Trigger已存在,那么更新相应的定时设置
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());

// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
e.printStackTrace();
LogKit.error("", e);
}
}

@Override
public boolean start() {
loadJobsFromProperties();
startJobs();
return true;
}

private void startJobs() {
try {
if (StrKit.notBlank(confConfig)) {
sf = new StdSchedulerFactory(confConfig);
} else {
sf = new StdSchedulerFactory();
}
scheduler = sf.getScheduler();
} catch (SchedulerException e) {
e.printStackTrace();
LogKit.error("", e);
}
for (JobBean entry : jobs) {
addJob(entry);
}
try {
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
LogKit.error("", e);
}
}

private void loadJobsFromProperties() {
if (StrKit.isBlank(jobConfig)) {
return;
}

jobProp = PropKit.use(jobConfig).getProperties();
String jobArray = PropKit.use(jobConfig).get("jobArray");
if (StrKit.isBlank(jobArray)) {
return;
}
String[] jobArrayList = jobArray.split(",");
for (String jobName : jobArrayList) {
jobs.add(createJobBean(jobName));
}
}

private JobBean createJobBean(String key) {
JobBean job = new JobBean();
job.setJobGroup(key);
job.setJobClass(jobProp.getProperty(key + ".job" , ""));
job.setCronExpression(jobProp.getProperty(key + ".cron" , ""));
job.setJobDesc(jobProp.getProperty(key + ".desc" , ""));
return job;
}

@Override
public boolean stop() {
try {
scheduler.shutdown();
} catch (SchedulerException e) {
e.printStackTrace();
LogKit.error("", e);
}
return true;
}
}



============ job 类====================


package com.wjme.app.job;

import com.jfinal.kit.HttpKit;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.PropKit;
import com.jfinal.server.undertow.UndertowConfig;
import com.wjme.App;
import com.wjme.app.busi.DataInfo;
import com.wjme.app.util.DES3Util;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class AutoIP implements Job {

Logger log = LoggerFactory.getLogger(getClass());

private static String currIP = "";
private String serverPath = PropKit.get("serverPath");
private String clientPath = PropKit.get("clientPath");
private int cPort = new UndertowConfig(App.class).getPort();
private int port =PropKit.getInt("clientPort", cPort);
private boolean clientRedirect =PropKit.getBoolean("clientPort", false);

@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("xxxxx");


}
}



===============JfinalConfig ====================


/**
* 配置插件
*/
public void configPlugin(Plugins me) {

QuartzPlugin quartz = new QuartzPlugin();
me.add(quartz);

}

=================quartz.properties ======================

#开启的任务列表“,”隔开
jobArray = autoip


autoip.job=com.wjme.app.job.AutoIP
autoip.cron= 0/10 * * * * ?
autoip.desc=autoip




#============================================================================
# 配置主要调度程序属性
#============================================================================
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false

#============================================================================
# 配置线程池
#============================================================================
org.quartz.threadPool.threadCount = 5
org.quartz.threadPool.threadPriority = 5

#============================================================================
# 配置任务
#============================================================================
org.quartz.jobStore.misfireThreshold = 1800
org.quartz.scheduler.skipUpdateCheck = true

JFinal

2020-03-15 17:35

@WJME 你用的是 quartz,这个在 jfinal 官方并未提供,jfinal 提供的是 Cron4jPlugin, 注意看文档:
https://jfinal.com/doc/9-2

WJME

2020-03-16 10:17

@JFinal 波总,主要Cron4jPlugin 不支持秒级调度,不然肯定首选官方插件啊。波总秒级调度还是比较常见的场景啊

JFinal

2020-03-16 11:47

@WJME quartz 太庞大,要引入很多 jar 包, 而 cron4j 则十分轻量小巧

并且,quartz 的使用本质与 jfinal 是无关的,只要会用 quartz 就可以用了,所以 jfinal 也无需对 quartz 进行过多干预

WJME

2020-03-16 12:54

@JFinal 倒也是,依赖太多违背精简思想,但是插件机制不知是否有问题,
现在有个bug,用JfinalConfig配置注册插件quartz调度不行,而且启动时也不报错,日志也是DEBUG等级

/**
* 配置插件
*/
public void configPlugin(Plugins me) {
QuartzPlugin quartz = new QuartzPlugin();
me.add(quartz);
}

但是改在main 调用就可以,太诡异。。。

/**
* 启动入口,运行此 main 方法可以启动项目
*/
public static void main(String[] args){
UndertowServer.start(AppConfig.class);

QuartzPlugin quartz = new QuartzPlugin();
quartz.start();
}

JFinal

2020-03-16 18:37

@WJME 在 jfinal 中使用任何第三方,不一定需要使用插件机制,而是直接用上即可

插件机制不是必要的

xialinlin

2020-03-17 09:08

quartz 挺好用的。集成也 简单。