`

Spring Boot集成Quartz-动态任务管理

    博客分类:
  • java
 
阅读更多

copy from:http://wuxinshui.github.io/spring%20boot/2017/08/28/Spring-Boot集成Quartz-动态任务管理.html

 

前言

当定时任务越来越多时,集中管理Job越有必要。Quartz提供了一组丰富的API,来管理Job。

Spring Boot 定时任务之Quartz中讲了Spring Boot怎么集成quartz,这里结合实际业务,参考网上一些经验,总结一下集成的一些坑。

动态任务管理

下面以官方的例子来说明一下这些常用的API。

定义Job实现类

public class ColorJob implements Job {

	public ColorJob() {
		// Instances of Job must have a public no-argument constructor.
	}

	public void execute(JobExecutionContext context)
			throws JobExecutionException {

		JobDataMap data = context.getMergedJobDataMap();
		System.out.println("someProp = " + data.getString("someProp"));
	}

}

定义JobDetail Trigger 

// Define job instance
JobDetail job1 = newJob(ColorJob.class)
    .withIdentity("job1", "group1")
    .build();

// Define a Trigger that will fire "now", and not repeat
Trigger trigger1 = newTrigger()
    .withIdentity("trigger1", "group1")
    .startNow()
    .build();

新建

把Job添加到调度器sched中。

// Add the the job to the scheduler's store
sched.add(job1, trigger1);

更新

TriggerKey triggerKey = TriggerKey.triggerKey("job1", "group1");
// store, and set overwrite flag to 'true'  
scheduler.addJob(job1, true);
// tell the scheduler to remove the old trigger with the given key, and put the new one in its place
scheduler.rescheduleJob(triggerKey, trigger1);

删除

JobKey jobKey = JobKey.jobKey("job1", "group1");
scheduler.deleteJob(jobKey);

暂停

JobKey jobKey = JobKey.jobKey("job1", "group1");
scheduler.pauseJob(jobKey);

恢复

JobKey jobKey = JobKey.jobKey("job1", "group1");
scheduler.resumeJob(jobKey);

立即执行

JobKey jobKey = JobKey.jobKey("job1", "group1");
scheduler.triggerJob(jobKey);

对Job的动态管理实际就是对调度器schedule中的JobDetail做动态操作。增删改逻辑不想其他业务逻辑一样,直接操作数据库。它是先操作schedule中的JobDetail,然后根据JobKey或者TriggerKey同步更新数据库的Job。

实际开发中常用的也就是这几种操作,quartz还有其他多种操作。如暂停所有的Job、打断正在执行的Job等。感兴趣的同学可以参考官网API:org.quartz.core.QuartzScheduler

加载Job

要实现Job的动态管理,Job必须要持久化到数据库。Spring 容器在启动的时候,从数据库加载所有的Job。

实现接口CommandLineRunner。定义初始化操作。

   @Override
    public void run(String... strings) throws Exception {
        //查询数据库中的Job
        List<JobInfo> jobInfoList = jobInfoMapper.selectAll();
        List<JobInfoVo> jobInfoVoList = BeanUtils.copyList(jobInfoList, JobInfoVo.class);

        //根据数据库中Job的状态同步scheduler中的状态。
        for (int i = 0; i < jobInfoVoList.size(); i++) {
            JobInfoVo jobVo = jobInfoVoList.get(i);
            Class jobClass = Class.forName(jobVo.getJobClass());

            JobKey jobKey = JobKey.jobKey(jobVo.getJobName(), jobVo.getJobGroup());
            TriggerKey triggerKey = TriggerKey.triggerKey(jobVo.getTriggerName(), jobVo.getTriggerGroup());
            JobDetail job1 = newJob(jobClass)
                    .withIdentity(jobKey)
                    .storeDurably()
                    .build();
            Trigger trigger = newTrigger().withSchedule(CronScheduleBuilder.cronSchedule(jobVo.getCronExpression()))
                    .withIdentity(triggerKey)
                    .build();

            JobStatus jobStatus = JobStatus.valueOf(jobVo.getJobStatus());
            switch (jobStatus) {
                case RUNNING:
                    scheduler.scheduleJob(job1, trigger);
                    break;
                case PAUSE:
                    scheduler.scheduleJob(job1, trigger);
                    scheduler.pauseJob(jobKey);
            }
        }
        //添加Job监听器
        QuartzJobListener quartzJobListener = new QuartzJobListener("quartzListener",jobManagerService);
        scheduler.getListenerManager().addJobListener(quartzJobListener, allJobs());
    }

下面总结一下,根据项目需要,遇到的一些问题。。

坑一:初始化调度器

Spring提供了xml、注解、Java配置、groovy配置实现Bean的创建和注入。通过xml来配置quartz是非常方便的,但是在Spring Boot中不推荐xml文件配置,采用Java配置来实现。

1.使用初始化Job

一开始初始化调度器是参考官网34.6 Using the Quartz Scheduler来实现Java配置的。

这里写图片描述

使用这种方式有个问题:必须创建一个空的Job实现类,来实现Schedule的初始化。

2.SchedulerFactory获取Schedule

@Configuration
public class QuartzConfig {

	@Bean(name = "scheduler")
	public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {

		SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
		factoryBean.setJobFactory(quartzJobFactory);
		factoryBean.afterPropertiesSet();
		Scheduler scheduler=factoryBean.getScheduler();
		scheduler.start();
		return scheduler;
	}
}

从1->2,是问题的一个解决优化的过程。

坑二:Spring Bean不能注入Job的实现类中

QuartzConfig 中添加以下bean

	//解决Job中注入Spring Bean为null的问题
	@Component("quartzJobFactory")
	private class QuartzJobFactory extends AdaptableJobFactory {
		//这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.
		@Autowired
		private AutowireCapableBeanFactory capableBeanFactory;

		protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
			//调用父类的方法
			Object jobInstance = super.createJobInstance(bundle);
			//进行注入,这属于Spring的技术,不清楚的可以查看Spring的API.
			capableBeanFactory.autowireBean(jobInstance);
			return jobInstance;
		}
	}

Job的实现类中添加以下代码:

	protected void springBeanAutowiringSupport() {
		SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
	}

坑三:保存Job执行记录

保存执行记录也有2种设计方案。

方案1:每个Job执行时保存

Job在执行时,调用业务bean中的方法,保存执行记录。

这里写图片描述

方案2:添加监听器JobListenerSupport

Quartz提供的监听器有JobListenerTriggerListener,这里我们使用JobListener,该监听器接口有三个方法:

这里写图片描述

实现接口JobListener,定义监听业务。

这里写图片描述

添加监听器到调度器schedule中。

 scheduler.getListenerManager().addJobListener(quartzJobListener, allJobs()); 

为了减少对Job的侵入性,建议在监听器中做业务逻辑的相关操作。Job只负责执行即可,不负责业务逻辑处理。

坑四:Job监听器中注入业务Bean

坑二是在Job中注入业务bean,发现在JobListenerSupport中注入Bean也是为null。之前的填坑方法不管用了。。。

可以通过构造方法来注入。

这里写图片描述

 QuartzJobListener quartzJobListener = new QuartzJobListener("quartzListener",jobManagerService); scheduler.getListenerManager().addJobListener(quartzJobListener, allJobs());

坑五:Job并发

quartz中的Job并发有2种情况

  1. 间隔时间小于执行时间,上一个任务还未完成,开始执行新的任务;
  2. 同一个Job,有相同的触发时间。

第二种情况设计上可以避免,cron定时表达式,能满足大部分情况下的使用,完全没有必要创建2个触发时间相同的Job。

第一种情况下的并发,可以使用注解@DisallowConcurrentExecution

这里写图片描述

加上注解以后,如果第一次执行未完成,第二次会等待直到第一次完成。

参考

Spring Boot配置方式 34.6 Using the Quartz Scheduler

参考的东西太多了,都是一些优秀的博客。。。

1.校验定时表达式

http://blog.csdn.net/lisheng19870305/article/details/39553925
http://blog.csdn.net/ukulelepku/article/details/54310035
https://stackoverflow.com/questions/2362985/verifying-a-cron-expression-is-valid-in-java
https://gist.github.com/andrew-templeton/ae4126a8efe219b796a3
https://codereview.stackexchange.com/questions/63363/cron-expression-validator-for-apache-quartz

2.Job中注入Spring Bean为Null

http://blog.csdn.net/jackylovesjava/article/details/50044271
http://blog.csdn.net/colorandsong/article/details/40392117
http://bbs.csdn.net/topics/392182530
http://www.cnblogs.com/feiqihang/p/5358100.html
http://blog.csdn.net/colorandsong/article/details/40392117
http://www.cnblogs.com/feiqihang/p/5358100.html
http://blog.csdn.net/educast/article/details/73331398
http://blog.csdn.net/gui66497/article/details/53589476
https://zhidao.baidu.com/question/984255639590451619.html
http://www.cnblogs.com/daxin/p/3608320.html
https://www.zhihu.com/question/26850120

3.Quartz日志处理

https://stackoverflow.com/questions/22573824/quartz-schedular-triggers-histoy-need-save-in-data-base-after-firing
https://stackoverflow.com/questions/22479622/how-to-maintain-the-quartz-triggers-history-in-data-base-after-firing-in-java
https://www.quartz-scheduler.net/documentation/faq.html
https://github.com/Flipkart/quartz/blob/master/quartz-plugins/src/main/java/org/quartz/plugins/history/LoggingTriggerHistoryPlugin.java

4.quartz动态任务管理

http://blog.csdn.net/u012907049/article/details/73801122
https://help.aliyun.com/document_detail/43140.html?spm=5176.doc43132.6.696.srgKu4

5.Quartz官网实践

http://www.quartz-scheduler.org/documentation/best-practices.html#listeners-(triggerlistener-joblistener-schedulerlistener


http://www.quartz-scheduler.org/documentation/quartz-2.2.x/cookbook/JobListeners.html

6.quartz任务并发

http://blog.csdn.net/tiantangpw/article/details/41120137
https://segmentfault.com/a/1190000009128328
https://my.oschina.net/blueskyer/blog/325812

7.暂停是否影响当前正在运行的Job。删除?

https://stackoverflow.com/questions/27823159/difference-between-pausejob-and-pausetrigger-in-quartz-scheduler
http://forums.terracotta.org/forums/posts/list/4537.page
https://stackoverflow.com/questions/16173785/quartz-fails-to-delete-a-job-now-what

分享到:
评论

相关推荐

    spring-boot-Quartz-1.zip

    本案例中,我们将深入探讨如何在SpringBoot应用中集成Quartz定时任务框架,以及如何配置和运行每20秒执行一次的任务。 首先,我们需要在项目中添加Quartz的依赖。在SpringBoot应用的`pom.xml`或`build.gradle`文件...

    spring-boot集成quartz实现动态任务管理,支持集群

    通过以上步骤,你就可以在Spring Boot应用中成功集成Quartz,实现动态任务管理和集群支持。在实际业务场景中,你可以根据需求创建更多的Job和Trigger,或者自定义JobDataMap来传递参数。务必注意,对于大型、复杂的...

    spring-boot-starter-validation-1.3.5.RELEASE.zip

    它的“starter”组件是为了快速引入特定功能而设计的,例如这里的"spring-boot-starter-validation"是为了在Spring Boot应用中轻松集成JSR-303/JSR-349(Bean Validation)标准,进行数据校验。 2. **Bean ...

    spring boot + quartz 动态管理 分布式

    总之,"Spring Boot + Quartz 动态管理 分布式"的主题涵盖了Spring Boot的快速开发特性,Quartz的定时任务调度能力,以及在分布式环境下的任务管理。通过学习和实践,开发者能够构建出一个灵活、健壮的定时任务系统...

    spring-boot-web-restfulcrud代码示例

    它集成了大量的常用第三方库配置,如 JDBC、MongoDB、JPA、RabbitMQ、Quartz 等,使得开发者可以快速地构建稳定且生产级别的应用程序。 在“spring-boot-web-restfulcrud”这个项目中,我们关注的是如何使用 Spring...

    Springboot整合Quartz实现定时任务数据库动态配置

    Spring Boot作为一个轻量级的Java框架,提供了与各种定时任务库集成的能力,其中Quartz是一个广泛应用的开源作业调度框架。本篇文章将详细探讨如何在Spring Boot项目中整合Quartz,并通过MySQL数据库实现定时任务的...

    spring-boot-quartz

    Spring Boot 是一个流行的 Java 框架,用于简化Spring应用程序的初始设置和配置。...通过上述步骤,你已经掌握了在Spring Boot应用中集成和使用Quartz的基本知识,可以开始创建和管理自己的定时任务了。

    spring boot集成quartz定时器

    总结,Spring Boot集成Quartz定时器能够方便地创建和管理定时任务,同时利用Spring的依赖注入,使得Job可以灵活地调用其他服务或组件。这种方式使得我们的任务更加模块化和易于维护。在实际开发中,根据项目需求,...

    (源码)基于Spring Boot和Quartz的定时任务管理系统.zip

    # 基于Spring Boot和Quartz的定时任务管理系统 ## 项目简介 本项目是一个基于Spring Boot和Quartz框架的定时任务管理系统,旨在提供一个灵活、高效的任务调度解决方案。系统支持从Excel配置文件中读取任务信息,并...

    基于spring-boot+quartz的CRUD动态任务管理系统

    5. **Spring Boot集成Quartz**:集成Quartz到Spring Boot项目中,首先需要在`pom.xml`文件中引入Quartz的相关依赖,然后在Spring Boot的配置文件`application.properties`或`application.yml`中设置Quartz的配置参数...

    springboot2.3集成quartz定时任务持久化数据库,支持集群

    在本文中,我们将深入探讨如何在Spring Boot 2.3版本中集成Quartz定时任务,并实现其持久化到数据库,以便支持集群环境。这个过程的关键在于配置Quartz Scheduler,设置数据库连接,以及确保任务在多节点环境中能够...

    java-springboot-quartz-定时任务.zip

    在SpringBoot项目中集成Quartz,首先需要引入相关的依赖。在`pom.xml`文件中,我们需要添加Quartz和SpringBoot对Quartz支持的依赖: ```xml &lt;groupId&gt;org.springframework.boot &lt;artifactId&gt;spring-boot-starter...

    spring-boot学习demo.zip_DEMO_SpringBoot_spring boot_spring-boot_sp

    - 模块化:Spring Boot可以与其他Spring模块和第三方库无缝集成。 - 健康检查:提供健康检查API,方便监控应用状态。 - 可执行JAR:构建的JAR文件可以直接运行,无需额外的服务器环境。 3. **Spring Boot的核心...

    基于Spring Boot的Quartz任务调度系统.zip

    本项目是一个基于Spring Boot和Quartz的任务调度系统,旨在提供灵活的任务管理和调度功能。系统支持多种任务类型,包括Cron表达式任务和单次时间任务,并提供了丰富的任务管理接口。 主要功能 任务调度支持Cron...

    spring-boot-examples-master.zip

    5. **定时任务示例**:利用Spring Boot的TaskScheduler或Quartz实现定时任务。 6. **云服务示例**:如Docker化部署、服务发现(如Eureka、Consul)和配置中心(如Config Server)等。 7. **微服务示例**:展示如何...

    schedule-job, 基于Spring Boot Quartz 的分布式任务调度系统.zip

    【Spring Boot集成Quartz】 在Spring Boot中集成Quartz,首先需要添加Quartz和Spring Boot Starter Scheduler的依赖。在`pom.xml`文件中,添加如下依赖: ```xml &lt;groupId&gt;org.springframework.boot ...

    spring-boot-quartz.zip

    为了更灵活地管理和监控Quartz作业,可以使用Spring Boot Actuator提供的健康检查端点,或者集成Quartz的Web管理界面。此外,还可以通过Spring事件监听机制,在作业开始和结束时触发自定义逻辑。 总的来说,Spring ...

    spring-boot-reference-guide-zh-中文, spring-boot参考指南

    - **任务调度**:使用Spring Task或Quartz进行定时任务。 - **国际ization (i18n)**:支持多语言环境。 9. **部署** - **Fat JAR**:打包所有依赖为单一可执行JAR,方便部署。 - **Docker**:将Spring Boot应用...

    dynamic-datasource-spring-boot-starter-v3.5.1.zip

    提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。 提供 自定义数据源来源 方案(如全从数据库加载)。 提供项目启动后 动态增加移除数据源 方案。 提供Mybatis环境下的 纯读写分离 方案。 ...

    spring-boot使用quartz框架定时发送邮件

    在这个场景中,我们将讨论如何在Spring Boot中集成Quartz框架来实现定时发送邮件的功能,以及如何从数据库中读取数据生成报表。 首先,我们需要在Spring Boot项目中引入Quartz的相关依赖。在`pom.xml`或`build....

Global site tag (gtag.js) - Google Analytics