[整理]在Spring MVC中使用Quartz实现定时任务动态管理
2017-12-12 09:35
585 查看
项目应用中有许多定时任务,当需要修改定时器时,往往需要停服务,这不是我们想要的。
于是动态管理项目中的定时任务就成了要解决的问题。
项目原来的定时任务是直接使用spring自己的scheduled-tasks实现的,因为是无状态的,没法满足我们的需求。
需要改造原来的定时任务,实现StatefulMethodInvokingJob类来解决。
大概的思路是把定时任务的参数数据保存到数据库,应用启动的时候从数据库读取配置它们,通过页面来实时启动和关闭它们。
项目比较老,使用的quartz-all-1.6.jar,spring用的是4.0.5
1、首先定义entity和数据库表,实现数据库的CRUD,这里列出entity其它的很简单就不列出来了
2、改造定时任务,这里我们新建两个定时任务,一个打印三角形,一个打印菱形
3、编写定时任务管理器,实现对定时任务的开关
4、编写Contoller和页面,实现Web化管理,这里页面就不贴了
5、还差一点就是应用启动时自动加载数据库内的定时任务,这里需要实现一个ApplicationListener
好了,主要工作完成了,我们启动应用试一试
页面如下:
试验一下暂停:
暂停以后,控制台没有输出,恢复一下
其它的就不贴图了。就这样吧。
实际应用中发现一个缺陷是,定时任务内部使用Spring托管的bean进行依赖注入时会报空指针异常,这里需要改造SchedulerFactoryBean 。
于是动态管理项目中的定时任务就成了要解决的问题。
项目原来的定时任务是直接使用spring自己的scheduled-tasks实现的,因为是无状态的,没法满足我们的需求。
需要改造原来的定时任务,实现StatefulMethodInvokingJob类来解决。
大概的思路是把定时任务的参数数据保存到数据库,应用启动的时候从数据库读取配置它们,通过页面来实时启动和关闭它们。
项目比较老,使用的quartz-all-1.6.jar,spring用的是4.0.5
1、首先定义entity和数据库表,实现数据库的CRUD,这里列出entity其它的很简单就不列出来了
public class QuartzJobModel { private String jobId; private String jobName; private String targetClassName; private String cronExpression; private String jobStatus; private String runOnHoliday; private String jobDesc; private Date createTime; private String createrName; private Date updateTime; private String updaterName; // getter &setter }
2、改造定时任务,这里我们新建两个定时任务,一个打印三角形,一个打印菱形
public class PrintRhombusJob extends StatefulMethodInvokingJob { private static final Logger logger = Logger.getLogger(PrintRhombusJob.class); /** * @see org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean.MethodInvokingJob#executeInternal(org.quartz.JobExecutionContext) */ @Override protected void executeInternal(JobExecutionContext cts) throws JobExecutionException { logger.info("================== print rhombus job begin ================="); System.out.println("print rhombus"); logger.info("================== print rhombus job end ================="); } }
public class PrintTraingleJob extends StatefulMethodInvokingJob { private static final Logger logger = Logger.getLogger(PrintTraingleJob.class); /** * @see org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean.MethodInvokingJob#executeInternal(org.quartz.JobExecutionContext) */ @Override protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException { logger.info("================== print traingle job begin ================="); System.out.println("print traingle"); logger.info("================== print traingle job end ================="); } }
3、编写定时任务管理器,实现对定时任务的开关
@Component("quartzJobManager") public class QuartzJobManager { private static final Logger logger = Logger.getLogger(QuartzJobManager.class); @Autowired private SchedulerFactoryBean schedulerFactoryBean; @Autowired private QuartzJobDAO quartzJobDAO; /** 默认任务组名称 */ private static final String DEFAULT_JOB_GROUP_NAME = "DefaultJobGroup"; /** 默认触发器组名称 */ private static final String DEFAULT_TRIGGER_GROUP_NAME = "DefaultTriggerGroup"; /** * 加载数据库中已定义的定时任务 * * @Title: loadJobs * @Description: 加载数据库中已定义的定时任务 */ public void loadJobs() { List<QuartzJobModel> jobs = quartzJobDAO.getAll(); if (null != jobs && !jobs.isEmpty()) { for (QuartzJobModel job : jobs) { addJob(job); } } } /** * 重新加载数据库中已定义的定时任务 * * @Title: reloadJobs * @Description: 重新加载数据库中已定义的定时任务 */ public void reloadJobs() { removeAll(); loadJobs(); } /** * 添加一个新的定时任务 * * @Title: addJob * @Description: 添加一个新的定时任务 * @param job QuartzJobModel */ public void addJob(QuartzJobModel job) { Scheduler scheduler = schedulerFactoryBean.getScheduler(); try { // 使用"jobName+默认任务组名称"作为定时任务的Key JobDetail jobDetail = new JobDetail(job.getJobName(), DEFAULT_JOB_GROUP_NAME, Class.forName(job.getTargetClassName())); // 使用"jobName+默认触发器组名称"作为定时任务触发器的Key CronTrigger trigger = new CronTrigger(job.getJobName(), DEFAULT_TRIGGER_GROUP_NAME, job.getCronExpression()); scheduler.scheduleJob(jobDetail, trigger); logger.info("******注册定时任务:" + job + " ******"); if (!scheduler.isShutdown()) { scheduler.start(); } } catch (ClassNotFoundException e) { logger.error("注册定时任务失败:" + job + e.getMessage()); e.printStackTrace(); } catch (ParseException e) { logger.error("注册定时任务失败:" + job + e.getMessage()); e.printStackTrace(); } catch (SchedulerException e) { logger.error("注册定时任务失败:" + job + e.getMessage()); e.printStackTrace(); } } /** * 修改定时任务 * * @Title: modifyJob * @Description: 修改定时任务 * @param job QuartzJobModel */ public void modifyJob(QuartzJobModel job) { removeJob(job); addJob(job); } /** * 删除定时任务 * * @Title: removeJob * @Description: 删除定时任务 * @param job QuartzJobModel */ public void removeJob(QuartzJobModel job) { Scheduler scheduler = schedulerFactoryBean.getScheduler(); try { // 根据""暂停触发器 scheduler.pauseTrigger(job.getJobName(), DEFAULT_TRIGGER_GROUP_NAME); // 根据""移除触发器 scheduler.unscheduleJob(job.getJobName(), DEFAULT_TRIGGER_GROUP_NAME); // 根据""删除定时任务 scheduler.deleteJob(job.getJobName(), DEFAULT_JOB_GROUP_NAME); logger.info("******删除定时任务:" + job + " ******"); } catch (SchedulerException e) { logger.error("移除定时任务失败:" + job + e.getMessage()); e.printStackTrace(); } } /** * 移除所有定时任务 * * @Title: removeAll * @Description: 移除所有定时任务 */ public void removeAll() { List<QuartzJobModel> jobs = quartzJobDAO.getAll(); if (null != jobs && !jobs.isEmpty()) { for (QuartzJobModel job : jobs) { removeJob(job); } } } /** * 暂停定时任务 * * @Title: pauseJob * @Description: 暂停定时任务 * @param job QuartzJobModel */ public void pauseJob(QuartzJobModel job) { Scheduler scheduler = schedulerFactoryBean.getScheduler(); try { scheduler.pauseJob(job.getJobName(), DEFAULT_JOB_GROUP_NAME); logger.info("******暂停定时任务:" + job + " ******"); } catch (SchedulerException e) { logger.error("暂停定时任务失败:" + job + e.getMessage()); e.printStackTrace(); } } /** * 恢复定时任务 * * @Title: resumeJob * @Description: 恢复定时任务 * @param job QuartzJobModel */ public void resumeJob(QuartzJobModel job) { Scheduler scheduler = schedulerFactoryBean.getScheduler(); try { scheduler.resumeJob(job.getJobName(), DEFAULT_JOB_GROUP_NAME); logger.info("******恢复定时任务:" + job + " ******"); } catch (SchedulerException e) { logger.error("恢复定时任务失败:" + job + e.getMessage()); e.printStackTrace(); } } /** * 立刻执行一次任务 * * @Title: triggerJob * @Description: 立刻执行一次任务 * @param job QuartzJobModel */ public void triggerJob(QuartzJobModel job) { Scheduler scheduler = schedulerFactoryBean.getScheduler(); try { scheduler.triggerJob(job.getJobName(), DEFAULT_JOB_GROUP_NAME); logger.info("******立刻执行定时任务:" + job + " ******"); } catch (SchedulerException e) { logger.error(" 立刻执行定时任务失败:" + job + e.getMessage()); e.printStackTrace(); } } }
4、编写Contoller和页面,实现Web化管理,这里页面就不贴了
@Controller @RequestMapping(value = "/jobs") public class JobController extends BaseController { private static Logger logger = Logger.getLogger(JobController.class); @Autowired private QuartzJobService quartzJobService; @Autowired private QuartzJobManager quartzJobManager; @RequestMapping(value = "/list") public String list() { return "list"; } @RequestMapping(value = "/queryListByPage") @RunningControllerLog(description = "分页查询") public void queryListByPage(HttpServletRequest request, HttpServletResponse response) { Map<String, Object> params = HttpServletUtils .parseReqToSearchCondition(new String[] { "jobStatus", "runOnHoliday", "jobName" }, request); // 权限条件追加 PermUtils.appendPermParams(params); PageModel<QuartzJobModel> pageModel = new PageModel<>(request); pageModel.setSearchCdtns(params); try { pageModel = quartzJobService.findListByPage(pageModel); returnJSONData(response, pageModel.toJSONString()); } catch (Exception e) { logger.error("分页查询异常,异常信息:" + e); } } @RequestMapping(value = "/toAdd") public String toAdd() { return "add"; } @RequestMapping(value = "/add", method = RequestMethod.POST) public void add(HttpServletRequest request, HttpServletResponse response) { String jobName = request.getParameter("jobName"); String targetClassName = request.getParameter("targetClassName"); String cronExpression = request.getParameter("cronExpression"); String runOnHoliday = request.getParameter("runOnHoliday"); String jobDesc = request.getParameter("jobDesc"); Date date = new Date(); SysUser user = getSysUser(request); String userName = user.getUserName(); QuartzJobModel job = new QuartzJobModel(); job.setJobName(jobName); job.setTargetClassName(targetClassName); job.setCronExpression(cronExpression); if (!StringUtil.isEmpty(jobDesc)) { job.setJobDesc(jobDesc); } else { job.setJobDesc(""); } job.setRunOnHoliday(runOnHoliday); job.setJobStatus(JobStatusEnum.RUNNING.getValue()); job.setCreaterName(userName); job.setCreateTime(date); job.setUpdaterName(userName); job.setUpdateTime(date); quartzJobManager.addJob(job); logger.info("^^^^^^^(add " + job + " by " + getSysUser(request).getUserName() + ")^^^^^^"); int result = quartzJobService.save(job); returnJSONData(response, JSON.toJSONString(result)); } @RequestMapping(value = "/toEdit/{jobId}") public String toEdit(HttpServletRequest request, HttpServletResponse response, @PathVariable("jobId") String jobId) { QuartzJobModel job = quartzJobService.getById(jobId); request.setAttribute("item", job); return "edit"; } @RequestMapping(value = "/edit", method = RequestMethod.POST) public void edit(HttpServletRequest request, HttpServletResponse response) { String jobId = request.getParameter("jobId"); String cronExpression = request.getParameter("cronExpression"); String runOnHoliday = request.getParameter("runOnHoliday"); String jobDesc = request.getParameter("jobDesc"); Date date = new Date(); SysUser user = getSysUser(request); String userName = user.getUserName(); QuartzJobModel job = quartzJobService.getById(jobId); job.setCronExpression(cronExpression); if (!StringUtil.isEmpty(jobDesc)) { job.setJobDesc(jobDesc); } else { job.setJobDesc(""); } job.setRunOnHoliday(runOnHoliday); job.setUpdaterName(userName); job.setUpdateTime(date); int result = quartzJobService.update(job); job = quartzJobService.getById(jobId); quartzJobManager.modifyJob(job); logger.info("^^^^^^^(edit " + job + " by " + getSysUser(request).getUserName() + ")^^^^^^"); returnJSONData(response, JSON.toJSONString(result)); } @RequestMapping(value = "/pause/{jobId}", method = RequestMethod.POST) public void pause(HttpServletRequest request, HttpServletResponse response, @PathVariable("jobId") String jobId) { Date date = new Date(); SysUser user = getSysUser(request); String userName = user.getUserName(); QuartzJobModel job = quartzJobService.getById(jobId); job.setJobStatus(JobStatusEnum.PAUSED.getValue()); job.setUpdaterName(userName); job.setUpdateTime(date); quartzJobManager.pauseJob(job); logger.info("^^^^^^^(pause " + job + " by " + getSysUser(request).getUserName() + ")^^^^^^"); int result = quartzJobService.update(job); returnJSONData(response, JSON.toJSONString(result)); } @RequestMapping(value = "/resume/{jobId}", method = RequestMethod.POST) public void resume(HttpServletRequest request, HttpServletResponse response, @PathVariable("jobId") String jobId) { Date date = new Date(); SysUser user = getSysUser(request); String userName = user.getUserName(); QuartzJobModel job = quartzJobService.getById(jobId); if (job.getJobStatus().equals(JobStatusEnum.PAUSED.getValue())) { quartzJobManager.resumeJob(job); } else if (job.getJobStatus().equals(JobStatusEnum.STOPPED.getValue())) { quartzJobManager.addJob(job); } logger.info("^^^^^^^(sesume " + job + " by " + getSysUser(request).getUserName() + ")^^^^^^"); job.setJobStatus(JobStatusEnum.RUNNING.getValue()); job.setUpdaterName(userName); job.setUpdateTime(date); int result = quartzJobService.update(job); returnJSONData(response, JSON.toJSONString(result)); } @RequestMapping(value = "/run/{jobId}", method = RequestMethod.POST) public void runJob(HttpServletRequest request, HttpServletResponse response, @PathVariable("jobId") String jobId) { QuartzJobModel job = quartzJobService.getById(jobId); logger.info("^^^^^^^(run " + job + " by " + getSysUser(request).getUserName() + ")^^^^^^"); quartzJobManager.triggerJob(job); } @RequestMapping(value = "/reloadJobs", method = RequestMethod.POST) public void reloadJobs(HttpServletRequest request, HttpServletResponse response) { logger.info("^^^^^^^(reload jobs by " + getSysUser(request).getUserName() + ")^^^^^^"); quartzJobManager.reloadJobs(); } @RequestMapping(value = "/remove/{jobId}", method = RequestMethod.POST) public void remove(HttpServletRequest request, HttpServletResponse response, @PathVariable("jobId") String jobId) { QuartzJobModel job = quartzJobService.getById(jobId); logger.info("^^^^^^^(remove job " + job + " by " + getSysUser(request).getUserName() + ")^^^^^^"); quartzJobManager.removeJob(job); job.setJobStatus(JobStatusEnum.STOPPED.getValue()); int result = quartzJobService.update(job); returnJSONData(response, JSON.toJSONString(result)); } @RequestMapping(value = "/getJobStatus", method = RequestMethod.POST) public void getJobStatus(HttpServletRequest request, HttpServletResponse response) { StringBuilder options = new StringBuilder(); List<JobStatusEnum> list = JobStatusEnum.getAll(); options.append("<option value=''>--请选择--</option>"); for (JobStatusEnum item : list) { options.append("<option value='" + item.getValue() + "'>" + item.getName() + "</option>"); } String json = "{\"html\":\"" + options.toString() + "\"}"; returnJSONData(response, json); } }
5、还差一点就是应用启动时自动加载数据库内的定时任务,这里需要实现一个ApplicationListener
@Component("StartupListener") public class InitSystemJobsListener implements ApplicationListener<ContextRefreshedEvent> { private int runTime = 0; /** * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) */ @Override public void onApplicationEvent(ContextRefreshedEvent event) { runTime++; if (2 == runTime) { // 获取spring管理的Bean ApplicationContext context = event.getApplicationContext(); QuartzJobManager quartzJobManager = (QuartzJobManager) context.getBean("quartzJobManager"); quartzJobManager.loadJobs(); } } }
好了,主要工作完成了,我们启动应用试一试
页面如下:
试验一下暂停:
暂停以后,控制台没有输出,恢复一下
其它的就不贴图了。就这样吧。
实际应用中发现一个缺陷是,定时任务内部使用Spring托管的bean进行依赖注入时会报空指针异常,这里需要改造SchedulerFactoryBean 。
@Component public class MyJobFactory extends AdaptableJobFactory { @Autowired private AutowireCapableBeanFactory autowireCapableBeanFactory; /** * @see org.springframework.scheduling.quartz.AdaptableJobFactory#createJobInstance(org.quartz.spi.TriggerFiredBundle) */ @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Object jobInstance = super.createJobInstance(bundle); // 实现Job的IOC管理 autowireCapableBeanFactory.autowireBean(jobInstance); return jobInstance; } }
@Configuration @EnableScheduling public class QuartzJobConfig { @Autowired private MyJobFactory myJobFactory; @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setOverwriteExistingJobs(true); factory.setStartupDelay(20); factory.setJobFactory(myJobFactory); return factory; } }
相关文章推荐
- spring mvc quartz 实现动态定时任务管理
- Spring动态对Quartz定时任务的管理,实现动态加载,停止的配置实例代码
- 使用Java并发包线程池和XML实现定时任务动态配置和管理
- Quartz+Spring Boot实现动态管理定时任务
- 定时任务-quartz的使用,实现可页面化管理 标签: quartz
- 使用 Quartz 实现任务的动态管理
- 定时任务-quartz的使用,实现可页面化管理
- Spring 动态管理定时任务(使用quartz) 只是管理启动时间 不能做启动和暂停
- 定时任务-quartz的使用,实现可页面化管理
- Spring动态对Quartz定时任务的管理,实现动态加载,停止的配置实例代码
- Spring动态对Quartz定时任务的管理,实现动态加载,停止的配置实例代码
- [置顶] spring整合quartz实现动态定时任务的前台网页配置与管理
- 定时任务-quartz的使用,实现可页面化管理
- Spring动态对Quartz定时任务的管理,实现动态加载,停止的配置实例代码
- Spring 3整合Quartz 2实现定时任务三:动态暂停 恢复 修改和删除任务
- Spring 3整合Quartz 2实现定时任务三:动态暂停 恢复 修改和删除任务
- Quartz定时任务在Spring MVC 中的实现
- Spring 3整合Quartz 2实现定时任务三:动态暂停 恢复 修改和删除任务
- 使用System.Threading的Timer&Quartz.net两种方式实现定时执行任务,防止IIS释放timer对象
- spring3整合quartz2,实现动态添加、修改、暂停、重启定时任务