spring.xml中<beans 中添加
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd
添加扫描包
<task:annotation-driven/>
<context:component-scan base-package="com.ruiger.common.task"/>
创建定时任务
package com.ruiger.common.task;
import java.util.Date;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class AttendTask {
@Autowired
IRecordService recordService;
private static Logger logger = Logger.getLogger(AttendTask.class);
// 每小时1分执行
@Scheduled(cron="0 1 0/1 * * ? ")
public void saveRecordIn1h(){
System.out.println("test")
}
}
时间设置参看cron表达式
spring.xml中<beans 中添加
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.1.xsd
添加扫描包
<task:annotation-driven/>
<context:component-scan base-package="com.ruiger.common.task"/>
package com.ruiger.common.task;
import java.util.Date;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import com.ruiger.common.utils.StringUtil;
@Component
@Lazy(false)
@EnableScheduling
public class TestTask implements SchedulingConfigurer {
public static String cron = "10 0/1 * * * ? ";
public void setCron(final String cron){
this.cron = cron;
}
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(new Runnable() {
@Override
public void run() {
// 需要实现的方法
System.out.println(String.format("测试1:%s", StringUtil.getDateStr(new Date(), "yyyy-MM-dd HH:mm:ss")));
}
}, new Trigger(){
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
//任务触发,可修改任务的执行周期
CronTrigger trigger = new CronTrigger(cron);
Date nextExec = trigger.nextExecutionTime(triggerContext);
return nextExec;
}
});
}
}
TestTask m = new TestTask();
m.setCron("15 0/1 * * * ? ");
修改后,本分钟内不会执行新任务(即使时间未到),下一分钟会执行旧新两次任务
每分钟一次的定时任务
10 0/1 * * * ? → 0 29 11 * * ?
修改后,本分钟内不会执行新任务(即使时间未到),下一分钟会执行旧新两次任务
测试1:2019-11-14 11:38:10
测试1:2019-11-14 11:39:10
测试1:2019-11-14 11:39:15
按秒间隔的定时任务
0/10 * * * * ? → 0/15 * * * * ?
修改后,会再执行一次旧任务,然后再应用新时间
测试1:2019-11-14 12:01:50
测试1:2019-11-14 12:02:00
测试1:2019-11-14 12:02:15
package com.ruiger.common.task;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruiger.common.utils.StringUtil;
@RestController
@Component
public class TestTask {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
private ScheduledFuture<?> future;
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
@RequestMapping("/startCron")
public String startCron() {
if(future == null || future.isCancelled()) {
future = threadPoolTaskScheduler.schedule(new MyRunnable(), new CronTrigger("0/10 * * * * *"));
System.out.println("DynamicTask.startCron()");
}
return "startCron";
}
@RequestMapping("/stopCron")
public String stopCron() {
if (future != null) {
future.cancel(true);
}
System.out.println("DynamicTask.stopCron()");
return "stopCron";
}
@RequestMapping("/changeCron10")
public String startCron10() {
stopCron();// 先停止,在开启.
future = threadPoolTaskScheduler.schedule(new MyRunnable(), new CronTrigger("0/15 * * * * *"));
System.out.println("DynamicTask.startCron10()");
return "changeCron10";
}
private class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(String.format("test1:%s", StringUtil.getDateStr(new Date(), "yyyy-MM-dd HH:mm:ss")));
}
}
}
quartz-2.3.2.jar quartz-jobs-2.3.2.jar
<!-- 初始化Scheduler -->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" />
package com.ruiger.common.quartz;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
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 org.springframework.stereotype.Component;
@Component
public abstract class SchedulerUtils implements ApplicationContextAware {
private static final Logger logger= LoggerFactory.getLogger(SchedulerUtils.class);
private static ApplicationContext appContext;
public static SchedulerFactoryBean schedulerFactoryBean = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (appContext == null) {
appContext = applicationContext;
}
// spring 启动时初始化SchedulerFactoryBean
schedulerFactoryBean = (SchedulerFactoryBean) appContext.getBean(SchedulerFactoryBean.class);
logger.info("setApplicationContext");
}
public static <T extends Job> void addJob(Object id, String cron, String groupName, Class<T> clazz) throws SchedulerException {
addJob(id, cron, groupName, clazz, null);
}
/**
* 添加任务
*
* @param scheduleJob
* @throws SchedulerException
*/
public static <T extends Job> void addJob(Object id, String cron, String groupName, Class<T> clazz, Map<String, Object> extras) throws SchedulerException {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(id.toString(), groupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 不存在,创建一个
if (null == trigger) {
JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(id.toString(), groupName).build();
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
TriggerBuilder<CronTrigger> triggerBuilder = TriggerBuilder.newTrigger().withDescription(id.toString())
.withIdentity(id.toString(), groupName).withSchedule(scheduleBuilder);
// 在trigger中额外数据
// 当trigger中已有键值时,triggerBuilder.usingJobData(JobDataMap) 无效??
if(extras != null) {
// triggerBuilder.usingJobData(new JobDataMap(extras));
for(Map.Entry<String, Object> entity : extras.entrySet()) {
triggerBuilder.usingJobData(entity.getKey(), entity.getValue().toString());
}
}
trigger = triggerBuilder.build();
scheduler.scheduleJob(jobDetail, trigger);
logger.info(String.format("quartz job new: %s %s %s", id, cron, groupName));
} else {
// Trigger已存在,那么更新相应的定时设置
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
// 按新的cronExpression表达式重新构建trigger
TriggerBuilder<CronTrigger> triggerBuilder = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder);
if(extras != null) {
// triggerBuilder.usingJobData(new JobDataMap(extras));
for(Map.Entry<String, Object> entity : extras.entrySet()) {
triggerBuilder.usingJobData(entity.getKey(), entity.getValue().toString());
}
}
trigger = triggerBuilder.build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
logger.info(String.format("quartz job update: %s %s %s", id, cron, groupName));
}
}
public static void delJob(Object id, String groupName) throws Exception {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobKey jobKey = JobKey.jobKey(id.toString(), groupName);
if(jobKey != null) {
scheduler.deleteJob(jobKey);
logger.info(String.format("quartz job delete: %s %s", id, groupName));
}else {
logger.info(String.format("quartz job delete: %s %s, but the job is not exist", id, groupName));
}
}
public static String getCron(Date date) {
Calendar c = Calendar.getInstance();
c.setTime(date);
return String.format("%d %d %d %d %d ? %d", c.get(Calendar.SECOND), c.get(Calendar.MINUTE), c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.DATE), c.get(Calendar.MONTH) + 1, c.get(Calendar.YEAR));
}
public static String getCron(Date date, int advMinutes) {
Calendar c = Calendar.getInstance();
c.setTimeInMillis(date.getTime() - advMinutes * 60 * 1000);
return String.format("%d %d %d %d %d ? %d", c.get(Calendar.SECOND), c.get(Calendar.MINUTE), c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.DATE), c.get(Calendar.MONTH) + 1, c.get(Calendar.YEAR));
}
public static String getMinutesStr(int minutes) {
int h = minutes / 60;
int m = minutes % 60;
return (h > 0 ? (String.format("%d小时", h)) : "") + (h == 0 || m > 0 ? (String.format("%d分钟", m)) : "");
}
}
实现job接口,任务触发时execute(JobExecutionContext context)方法被回调
package com.ruiger.common.quartz;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ruiger.common.msg.MsgHttpUtils;
import com.ruiger.model.space.oa.Todo;
import com.ruiger.service.space.oa.ITodoService;
@Component
public class TodoJob implements Job {
private static final Logger logger= LoggerFactory.getLogger(TodoJob.class);
@Autowired
private ITodoService _todoService;
private static ITodoService todoService;
@PostConstruct
public void initService() {
todoService = _todoService;
}
public void execute(JobExecutionContext context) throws JobExecutionException {
JobKey jobKey = context.getJobDetail().getKey();
String id = jobKey.getName();
String groupName = jobKey.getGroup();
JobDataMap m = context.getTrigger().getJobDataMap();
Map<String, Object> map = m.getWrappedMap();
// 查询待办,如待办仍存在,发送提示通讯提醒,如不存在,说明文件已办,无需提醒
Todo todo = todoService.selectById(id);
if(todo != null) {
if(groupName.equals(TodoSchedulerUtils.GROUP_SIGN)) {
if(todo.getIsSign() == 0) {
// 未签收待办
logger.info(String.format("on todo notice, todo is unsigned: %s %s %s", groupName, todo.getId(), todo.getTodoTitle()));
// 发送即时消息
String title = String.format("您的待办【%s】已%s未签收,请尽快签收办理", todo.getTodoTitle(), SchedulerUtils.getMinutesStr(map.containsKey("time") ? Integer.valueOf(map.get("time").toString()) : 0));
MsgHttpUtils.pushMsgByCode(todo.getUserCode(), title, todo.getTodoTitle());
// 再次设置签到提醒
TodoSchedulerUtils.addSignNotice(todo, map);
}else {
logger.info(String.format("on todo notice, todo is signed, skiped: %s %s %s", groupName, todo.getId(), todo.getTodoTitle()));
}
}else if(groupName.equals(TodoSchedulerUtils.GROUP)) {
// 未办理
String title = String.format("您的待办【%s】已%s未办理,请尽快办理", todo.getTodoTitle(), SchedulerUtils.getMinutesStr(map.containsKey("time") ? Integer.valueOf(map.get("time").toString()) : 0));
// 发送即时消息
MsgHttpUtils.pushMsgByCode(todo.getUserCode(), title, todo.getTodoTitle());
// 再次设置办理提醒
TodoSchedulerUtils.addHandleNotice(todo, map);
}
}else {
logger.info(String.format("on todo notice: %s %s, todo is over(todo is null)", groupName, id));
}
}
}