springmvc使用定时任务quartz
springmvc使用定时任务quartz
项目需求
1.定时执行任务
2.可动态新增,修改,删除定时任务
jar包
<dependency><groupId>org.quartz-schedulergroupId><artifactId>quartzartifactId><version>2.2.1version>
dependency>
java实现类
1.job 工厂实例方法重写QuartzJobFactory
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;@Component
public class QuartzJobFactory extends AdaptableJobFactory {@Autowiredprivate AutowireCapableBeanFactory autowireCapableBeanFactory;/*** 重写job实例化方法* 将实例化对象手动添加到spring IOC容器并完成对象注入** @param bundle* @return* @throws Exception*/@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {//父类方法调用Object jobInstance = super.createJobInstance(bundle);//spring注入autowireCapableBeanFactory.autowireBean(jobInstance);return jobInstance;}
}
2.定时器中心处理器QuartzManager
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Date;@Service
public class QuartzManager {private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();@Autowiredprivate QuartzJobFactory quartzJobFactory;/*** 新增一个定时任务** @param jobName 任务名* @param jobGroupName 任务组名* @param triggerName 触发器名* @param triggerGroupName 触发器组名* @param jobClass 任务类* @param cron 时间设置* @param jobDataMap 任务参数*/@SuppressWarnings("unchecked")public void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName, Class jobClass, String cron, JobDataMap jobDataMap) {//调度类获取Scheduler scheduler = null;try {scheduler = schedulerFactory.getScheduler();//设置job实例工厂【实现手动spring注入】scheduler.setJobFactory(quartzJobFactory);//job实例与设置其所属身份JobDetail jobDetail = JobBuilder.newJob(jobClass).usingJobData(jobDataMap).withIdentity(jobName, jobGroupName).build();//触发器TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();//触发器身份所属设置triggerBuilder.withIdentity(triggerName, triggerGroupName);triggerBuilder.startNow();// 触发器时间设定triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));// 创建Trigger对象CronTrigger trigger = (CronTrigger) triggerBuilder.build();// 调度容器设置JobDetail和Triggerscheduler.scheduleJob(jobDetail, trigger);//启动if (!scheduler.isShutdown()) {scheduler.start();}System.out.println("新增定时任务=【" + jobName + "=" + jobGroupName + "】" + cron);} catch (SchedulerException e) {e.printStackTrace();System.out.println("新增定时任务【" + jobName + jobGroupName + "】失败");}}/*** 修改定时任务触发时间** @param jobName 任务名* @param jobGroupName 任务组名* @param triggerName 触发器名* @param triggerGroupName 触发器组名* @param cron 时间*/public void modifyJobTime(String jobName, String jobGroupName, String triggerName, String triggerGroupName, String cron) {Scheduler scheduler = null;try {scheduler = schedulerFactory.getScheduler();//获取触发器所属keyTriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);//如果触发器不存在,不往下执行if (trigger == null) {return;}//获取当前执行时间String cronExpression = trigger.getCronExpression();//新触发器时间与旧触发器时间不一致时修改触发器时间if (!cronExpression.equals(cron)) {/** 方式一 :调用 rescheduleJob 开始 */// 触发器TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();// 触发器名,触发器组triggerBuilder.withIdentity(triggerName, triggerGroupName);triggerBuilder.startNow();// 触发器时间设定triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));// 创建Trigger对象trigger = (CronTrigger) triggerBuilder.build();// 方式一 :修改一个任务的触发时间(覆盖旧数据)scheduler.rescheduleJob(triggerKey, trigger);/** 方式一 :调用 rescheduleJob 结束 *//** 方式二:先删除,然后在创建一个新的Job *///JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));//Class extends Job> jobClass = jobDetail.getJobClass();//removeJob(jobName, jobGroupName, triggerName, triggerGroupName);//addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);/** 方式二 :先删除,然后在创建一个新的Job */System.out.println("更新定时任务=【" + jobName + "=" + jobGroupName + "】" + cron);}} catch (SchedulerException e) {e.printStackTrace();System.out.println("更新定时任务【" + jobName + jobGroupName + "】失败");}}/*** 移除一个定时任务** @param jobName 任务名* @param jobGroupName 任务组名* @param triggerName 触发器名* @param triggerGroupName 触发器组名*/public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {Scheduler scheduler = null;try {scheduler = schedulerFactory.getScheduler();TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);scheduler.pauseTrigger(triggerKey);// 停止触发器scheduler.unscheduleJob(triggerKey);// 移除触发器scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务System.out.println("移除定时任务=【" + jobName + "=" + jobGroupName + "】");} catch (SchedulerException e) {e.printStackTrace();System.out.println("移除定时任务【" + jobName + jobGroupName + "】失败");}}/*** 启动所有定时任务*/public void startJobs() {try {Scheduler scheduler = schedulerFactory.getScheduler();scheduler.start();} catch (Exception e) {throw new RuntimeException(e);}}/*** 关闭所有定时任务*/public void shutdownJobs() {try {Scheduler scheduler = schedulerFactory.getScheduler();if (!scheduler.isShutdown()) {scheduler.shutdown();}} catch (Exception e) {throw new RuntimeException(e);}}
}
3自定义定时任务类(具体执行内容)
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.util.Date;
import java.util.List;@Component
public class ReminderJob implements Job {@Autowiredprivate EduScheduleService eduScheduleService;/*** 任务执行内容** @param jobExecutionContext*/@Overridepublic void execute(JobExecutionContext jobExecutionContext) {//参数获取JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();//逻辑代码编写}
}
4.使用样例
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.List;/*** @author ljc* @Title:* @Package* @Description: 启动监听类【项目启动完成或刷新完成时触发】* @date 2021/3/116:16*/
@Service
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {@Autowiredprivate QuartzManager quartzManager;@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {String cron = "0 0 12 * * ?";JobDataMap dataMap = new JobDataMap();dataMap.put("testName", "a");quartzManager.addJob("a", "a1", "b", "b1", ReminderJob.class, cron, dataMap);}
}
cron表达式详解link
5.项目停止时会发现报错
Web应用程序[edu_api]似乎启动了一个名为[DefaultQuartzScheduler_Worker-1]的线程,但未能停止它。这很可能会造成内存泄漏
这是因为项目停止时,而quartz未停止,可以监听事件来停止quartz的全部定时任务
import org.apache.commons.lang3.StringUtils;
import org.quartz.JobDataMap;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.util.HashMap;
import java.util.List;public class MyContextListener implements ServletContextListener {private QuartzManager quartzManager;private WebApplicationContext webApplicationContext;public void setQuartzManager(QuartzManager quartzManager) {this.quartzManager = quartzManager;}/*** 项目初始化** @param sce*/@Overridepublic void contextInitialized(ServletContextEvent sce) {}/*** 项目销毁** @param sce*/@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("销毁=======》>");if (webApplicationContext == null)webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());quartzManager = (QuartzManager) webApplicationContext.getBean("quartzManager");quartzManager.shutdownJobs();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}
}
web.xml 文件添加监听
<listener><listener-class>*.*.*MyContextListenerlistener-class>
listener>
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
