使用 Spring Boot 的 Quartz 指南

介绍

时间是宝贵的,委派时间和资源来执行琐碎的任务往往会浪费资源和金钱。因此,组织努力在其系统中实现全面自动化,因为它更具可扩展性且成本更低。

随着业务流程复杂性的增加,系统自动化的好处也在增加。

自动化作业调度程序概念流行的地方。作业调度通常被称为在给定时间执行的任何类型的批处理(作业)。由于这些作业中的大多数不需要立即执行,因此可以安排在不久的将来或以重复的时间间隔处理它们。

通常,通过手动方法自动化任何类型的流程会导致:

  • 资源效率
  • 更少的错误
  • 更多的可扩展性

用于大型 Java 应用程序的最强大和最灵活的调度框架之一被称为Quartz

在本指南中,我们将在 Spring Boot 应用程序中实现 Quartz 及其组件,为自定义Jobs和Triggers构建我们自己的Quartz 管理控制台。

注意:我们将要构建的Quartz 管理控制台的可运行的、成熟的副本在我们的 GitHub 上可用。

Quartz 作业调度程序

Quartz是一个用 Java 编写的开源、功能强大的作业调度框架,旨在与任何类型的 J2EE 或 J2SE 框架集成。它在不牺牲复杂性或可扩展性的情况下提供了巨大的灵活性。

据推测,这个名字来源于极其精确的钟表中使用的石英晶体,它在电振荡的作用下,使表针在固定的时间范围内移动。

如果应用程序需要按计划的时间间隔或由于某些事件执行任务,Quartz非常适合:

  • 触发电子邮件提醒或警报:您可以轻松地根据帐户活动向不同用户触发密码过期邮件或其他类型的提醒警报。
  • 执行文件传输或消息传递操作:可以轻松地按特定时间间隔安排作业,以发布/使用来自各种代理或 FTP 站点的消息/数据/文件。
  • 自动生成报告:公司通常更喜欢生成每晚/每周报告来展示业务绩效。这些作业可以轻松生成报告并在预定时间触发向员工发送电子邮件。
  • 推动任务工作流程:大型电子商务组织可以安排一个作业以特定的时间间隔精确触发,以从渠道中挑选订单并处理它以实现或表现。

Quartz 的一些显着特点是:

  • 它可以在应用程序服务器或 servlet 容器中实例化,并且可以参与 XA 事务。
  • 它可以托管为一组独立程序(具有负载平衡和故障转移功能)以执行作业。
  • 作业计划在触发发生时运行,例如一天中的某个时间、几周、几个月或几年中的某些天、在假期跳过执行、重复到某个日期或无限期等。
  • 作业可以保存在内存中或任何 JDBC 数据存储中。
  • 它可以参与 JTA 事务。

Quartz调度器模型的关键组件

为了提高可扩展性,Quartz多线程环境中运行。这有助于框架同时运行作业。

整个框架的核心是Scheduler接口。Scheduler为他们跟踪所有的sJobDetailTriggers。它们代表需要运行什么Job(哪个)和何时(Trigger那个工作是什么)。

因此,它们构成了框架的主要组成部分。所有其他组件的其余部分确保它通过尽职调查和有效地发生。

让我们从鹰的角度来看待我们将使用的关键组件:

  • Scheduler Factory – 工厂 bean,负责Scheduler根据石英属性文件的内容构建模型并在所有相关组件中进行布线。
  • Scheduler – 维护JobDetail / Trigger注册表。它还负责在触发器触发时执行相关的作业。
  • 调度程序线程– 负责执行触发触发器工作的线程。它联系JobStore以获取下一组要触发的触发器。
  • Job – 必须由要执行的任务实现的接口。
  • 触发器- 指示调度程序应该触发相关作业的时间。
  • JobStore – 由为作业和触发器提供存储机制的类实现的接口。
  • ThreadPool – 要执行的作业被转移到线程池,由ThreadPool.
  • 工作线程- 构建ThreadPool和执行作业的各个线程。
使用 Spring Boot 的 Quartz 指南

构建 Quartz 管理控制台

我们将构建自己的Quartz 管理控制台,以了解和欣赏 Quartz 调度程序中的生命周期。

为此,我们将构建一个简单的 UI 驱动的管理控制台,它可以执行两种任务:

  • 安排和管理简单的工作
  • 安排和管理 Cron 作业

实施后看起来像这样:

使用 Spring Boot 的 Quartz 指南

项目设置

让我们创建一个 Spring Boot 项目,并一个一个地实现每个 Quartz 组件。从骨架项目开始的最简单方法是通过Spring Initializr:

使用 Spring Boot 的 Quartz 指南

我们添加了用于 MVC 功能的Spring Web 、将数据存储到数据存储中的Spring Data JPA 、作为内存数据库的H2 、 Lombok(可选的样板减少库)和Thymeleaf(用于 Spring/MVC 应用程序的模板引擎)。我们还包含了spring-boot-starter-quartz将 Quartz 纳入我们的项目的包。

数据库连接和初始化

Quartz 引入了自己的内置JobStores。在 Spring Boot 中,我们可以选择:

  • In-Memory JobStores:将所有数据保存在 RAM 中,这样当应用程序停止或崩溃时,所有数据都被转储,所有调度信息都丢失。为此,我们使用RAMJobStore.
  • JDBC JobStores:持久化数据存储中的所有数据,这样数据就不会丢失。配置比内存 (RAM) 作业存储更复杂一些。

注意:JobStore无论您的数据库如何,您都可以选择这些类型。

我们将使用 H2 作为我们的数据存储,并设置 Quartz 来持久化数据。

Quartz 要求您为 JDBC JobStores 初始化数据库表,因为它们不是自动创建的。为此,我们将在初始化数据库时使用 SQL 脚本来运行。您可以在我们的 GitHub 上
找到初始化脚本。

让我们通过定义 H2 的数据库连接参数来开始我们的管理应用程序的开发。在您的application.properties文件中,让我们定义init.schema(初始设置脚本)以及datasource参数:

server.port=8080

spring.sql.init.schema-locations=classpath:db/quartz_tables_h2.sql
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.username=sa
spring.datasource.password=

logging.level.org.hibernate.SQL=debug

quartz_tables_h2.sql脚本由一组冗长的 SQL 命令组成,用于最初设置它:

-- Note, Quartz depends on row-level locking which means you must use the MVC=TRUE
-- setting on your H2 database, or you will experience dead-locks
--
-- In your Quartz properties file, you'll need to set
-- org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

CREATE TABLE QRTZ_CALENDARS (
  SCHED_NAME VARCHAR(120) NOT NULL,
  CALENDAR_NAME VARCHAR (200)  NOT NULL ,
  CALENDAR IMAGE NOT NULL
);

...
-- Download the entire script from our GitHub repository
...

COMMIT;

石英属性

一旦可以建立数据库连接并且我们已经准备好初始化脚本 - 我们将要设置Quartz 调度程序及其组件。

大多数方面和组件在一定程度上是可定制的,例如JobStore应该使用哪些驱动程序,其中有多少线程ThreadPool以及它们具有哪些优先级等。

All of these are defined in a quartz.properties file, which should be located under /src/resources/. This is the directory in which the QuartzProperties class looks for the required properties by default.

Note: If you want to define it in another property file, you'll have to point the org.quartz.properties system property to point to that file.

Let's define some of the properties now:

#============================================================================
# Configure Main Scheduler Properties
#============================================================================
org.quartz.scheduler.instanceName=spring-boot-quartz
org.quartz.scheduler.instanceId=AUTO 

#============================================================================
# Configure ThreadPool
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.misfireThreshold=1000
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties=true
org.quartz.jobStore.tablePrefix=QRTZ_


#============================================================================
# Configure Cluster properties
#============================================================================
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=1000

Defining a Scheduler Job Factory Bean

All of these properties don't mean much if we don't use them in a @Configuration class to customize how Quartz works. Let's inject the properties from quartz.properties into a SchedulerConfig class, where we'll initialize the SchedulerJobFactoryBean class, passing the properties in.

We'll be implementing our own SchedulerJobFactoryBean as a SpringBeanJobFactory from the Quartz project:

@Configuration
public class SchedulerConfig {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private QuartzProperties quartzProperties;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {

        SchedulerJobFactory jobFactory = new SchedulerJobFactory();
        jobFactory.setApplicationContext(applicationContext);

        Properties properties = new Properties();
        properties.putAll(quartzProperties.getProperties());

        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setOverwriteExistingJobs(true);
        factory.setDataSource(dataSource);
        factory.setQuartzProperties(properties);
        factory.setJobFactory(jobFactory);
        return factory;
    }
}

该类QuartzProperties包含文件中定义的属性quartz.properties。我们可以通过检索它们getProperties()并将它们添加到、和SchedulerFactoryBean旁边。DataSourceSchedulerJobFactory

这是Quartz 为我们提供SchedulerJobFactory的自定义实现。SpringBeanJobFactory让我们扩展它:

public class SchedulerJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {

    private AutowireCapableBeanFactory beanFactory;

    @Override
    public void setApplicationContext(final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }
}

现在,我们可以通过我们的工厂创造就业机会,并在需要时自动装配它。在这个阶段——我们可以启动一个正在运行的 Quartz 调度程序实例。如果我们运行我们的应用程序,我们会收到以下内容:

使用 Spring Boot 的 Quartz 指南

定义通用 Job Scheduler Creator

Quartz 中有两种类型的触发器 -CronTriggerSimpleTrigger. 它们分别对应于CronSchedulerSimpleScheduler,我们可以使用它们各自的工厂来创建触发器。

CronTrigger基于cron 表达式的触发器,而SimpleTrigger基于间隔的触发器。

为了创建作业触发器,让我们定义几个方便的方法,通过它们各自的工厂实例化并返回它们。这些方法将位于我们将用于创建作业和触发器的 -a 中JobSchedulerCreator@Component

@Component
public class JobScheduleCreator {
    // Creation methods
}

让我们从CronTrigger创建者方法开始:

public CronTrigger createCronTrigger(String triggerName, Date startTime, String cronExpression, int misFireInstruction) {
    CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
    factoryBean.setName(triggerName);
    factoryBean.setStartTime(startTime);
    factoryBean.setCronExpression(cronExpression);
    factoryBean.setMisfireInstruction(misFireInstruction);
    try {
      factoryBean.afterPropertiesSet();
    } catch (ParseException e) {
      log.error(e.getMessage(), e);
    }
    return factoryBean.getObject();
}

使用CronTriggerFactoryBean,我们传入有关 a 的所需信息Trigger,例如它的名称、开始时间以及 cron 表达式和 misfire 指令。一旦生成 - 返回对象。

几乎相同的过程适用于创建SimpleTrigger对象:

public SimpleTrigger createSimpleTrigger(String triggerName, Date startTime, Long repeatTime, int misFireInstruction) {
    SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
    factoryBean.setName(triggerName);
    factoryBean.setStartTime(startTime);
    factoryBean.setRepeatInterval(repeatTime);
    factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
    factoryBean.setMisfireInstruction(misFireInstruction);
    factoryBean.afterPropertiesSet();
    return factoryBean.getObject();
}

通过构建触发器的简单方法,我们还可以构建一个方便的方法来构建作业 - 依赖于JobDetailFactoryBean

public JobDetail createJob(Class<? extends QuartzJobBean> jobClass, boolean isDurable,
                           ApplicationContext context, String jobName, String jobGroup) {
    JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
    factoryBean.setJobClass(jobClass);
    factoryBean.setDurability(isDurable);
    factoryBean.setApplicationContext(context);
    factoryBean.setName(jobName);
    factoryBean.setGroup(jobGroup);

    // Set job data map
    JobDataMap jobDataMap = new JobDataMap();
    jobDataMap.put(jobName + jobGroup, jobClass.getName());
    factoryBean.setJobDataMap(jobDataMap);
    factoryBean.afterPropertiesSet();
    return factoryBean.getObject();
}

定义调度程序作业信息实体

要跟踪工作详细信息和信息 - 我们可以使用JobDetails该类。这就是它的意义所在。但是,我们可以从为我们自己的类定义代理中受益。

不建议自己直接写入 Quartz 表,因此作业及其详细信息虽然保留,但已修复。我们可以定义一个新实体来在单独的表中跟踪这些作业,并按照我们的意愿处理它们 - 同时还可以将这些对象用作数据传输对象 (DTO)。

这使我们能够对传入数据执行验证,并允许我们对作业在数据库中的持久化方式进行更精细的控制。

虽然是可选的,但建议使用这样的代理 - 我们将其命名为SchedulerJobInfo

// Lombok annotations for getters, setters and constructor
public class SchedulerJobInfo {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private String jobId;
    private String jobName;
    private String jobGroup;
    private String jobStatus;
    private String jobClass;
    private String cronExpression;
    private String desc;    
    private String interfaceName;
    private Long repeatTime;
    private Boolean cronJob;
}

对于简单的 CRUD 功能 - 我们将为JpaRepository这个实体创建一个简单的:

@Repository
public interface SchedulerRepository extends JpaRepository {
    SchedulerJobInfo findByJobName(String jobName);
}

在 Quartz 中实现 Job - Job 和 QuartzJobBean

每个作业都必须扩展QuartzJobBean类或实现Job接口。

QuartzJobBean实现Job,唯一的区别是QuartzJobBean应用传递JobDataMap的和SchedulerContextas bean 属性值,而Job没有。

此外,Job需要您实现该execute()方法,同时QuartzJobBean需要您实现该executeInternal()方法。

让我们创建一个SimpleJob,extends QuartzJobBean并打印从05的整数:

public class SimpleJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        log.info("SimpleJob Start................");
        IntStream.range(0, 5).forEach(i -> {
            log.info("Counting - {}", i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
        });
        log.info("SimpleJob End................");
    }
}

同样,我们可以创建一个SimpleCronJob在特定 cron 表达式上触发的函数:

@DisallowConcurrentExecution
public class SimpleCronJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        log.info("SimpleCronJob Start................");
        IntStream.range(0, 10).forEach(i -> {
            log.info("Counting - {}", i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
        });
        log.info("SimpleCronJob End................");
    }
}

注意:我们正在申请@DisallowConcurrentExecution,以便在集群设置中多个调度程序不会同时执行此作业。

为操作定义自定义实用程序

Quartz 管理控制台中,我们将有几个作业选项:

  • 创造
  • 编辑
  • 运行一次
  • 暂停
  • 恢复
  • 删除

这些允许我们创建、编辑、暂停、恢复、删除和运行一次作业。为了使这一点更加有趣 - 我们将为每个任务编写方法,使我们能够从一个非常简单直观的 UI 控制作业。

为了将这一切联系在一起,我们将创建一个新类 -SchedulerJobService来执行这些操作:

@Transactional
@Service
public class SchedulerJobService {

	@Autowired
	private Scheduler scheduler;

	@Autowired
	private SchedulerFactoryBean schedulerFactoryBean;

	@Autowired
	private SchedulerRepository schedulerRepository;

	@Autowired
	private ApplicationContext context;

	@Autowired
	private JobScheduleCreator scheduleCreator;
	
	// Create, edit, pause jobs, etc...

Create a Quartz Job

To create jobs, a proprietary saveOrUpdate() method determines whether the instance created via a specific SchedulerJobInfo DTO is to be saved into an existing entity or if a new job should be created. Based on the paramaters in the payload, we'll either create a SimpleCronJob or SimpleJob:

public void saveOrUpdate(SchedulerJobInfo scheduleJob) throws Exception {
	if (scheduleJob.getCronExpression().length() > 0) {
		scheduleJob.setJobClass(SimpleCronJob.class.getName());
		scheduleJob.setCronJob(true);
	} else {
		scheduleJob.setJobClass(SimpleJob.class.getName());
		scheduleJob.setCronJob(false);
		scheduleJob.setRepeatTime((long) 1);
	}
	if (StringUtils.isEmpty(scheduleJob.getJobId())) {
		log.info("Job Info: {}", scheduleJob);
		scheduleNewJob(scheduleJob);
	} else {
		updateScheduleJob(scheduleJob);
	}
	scheduleJob.setDesc("i am job number " + scheduleJob.getJobId());
	scheduleJob.setInterfaceName("interface_" + scheduleJob.getJobId());
	log.info(">>>>> jobName = [" + scheduleJob.getJobName() + "]" + " created.");
}

如果作业不存在 - 我们scheduleNewJob()使用之前的自动装配JobScheduleCreator组件调用 which 安排新作业:

private void scheduleNewJob(SchedulerJobInfo jobInfo) {
	try {
		Scheduler scheduler = schedulerFactoryBean.getScheduler();

		JobDetail jobDetail = JobBuilder
				.newJob((Class<? extends QuartzJobBean>) Class.forName(jobInfo.getJobClass()))
				.withIdentity(jobInfo.getJobName(), jobInfo.getJobGroup()).build();
		if (!scheduler.checkExists(jobDetail.getKey())) {

			jobDetail = scheduleCreator.createJob(
					(Class<? extends QuartzJobBean>) Class.forName(jobInfo.getJobClass()), false, context,
					jobInfo.getJobName(), jobInfo.getJobGroup());

			Trigger trigger;
			if (jobInfo.getCronJob()) {
				trigger = scheduleCreator.createCronTrigger(
				        jobInfo.getJobName(), 
				        new Date(),
						jobInfo.getCronExpression(),
						SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
			} else {
				trigger = scheduleCreator.createSimpleTrigger(
				        jobInfo.getJobName(), 
				        new Date(),
				        jobInfo.getRepeatTime(), 
				    
    SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
			}
			scheduler.scheduleJob(jobDetail, trigger);
			jobInfo.setJobStatus("SCHEDULED");
			schedulerRepository.save(jobInfo);
			log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " scheduled.");
		} else {
			log.error("scheduleNewJobRequest.jobAlreadyExist");
		}
	} catch (ClassNotFoundException e) {
		log.error("Class Not Found - {}", jobInfo.getJobClass(), e);
	} catch (SchedulerException e) {
		log.error(e.getMessage(), e);
	}
}

创建触发器时,我们传入一个MISFIRE_INSTRUCTION. 有时,Quartz 可能会错过某项工作。如果工作线程很忙,如果调度程序已关闭或过去计划触发作业,以及类似问题,则可能会发生这种情况。

我们已将触发器设置为MISFIRE_INSTRUCTION_FIRE_NOW- 如果发生失火,则会再次触发。如果没有MISFIRE_INSTRUCTION定义,Quartz 采用Smart Policy - MISFIRE_INSTRUCTION__SMART_POLICY

编辑 Quartz 作业

要编辑作业,我们可以使用与创建它们大致相同的方法 - 但是,我们必须通知调度程序在其指令更新后重新安排作业:

private void updateScheduleJob(SchedulerJobInfo jobInfo) {
	Trigger newTrigger;
	if (jobInfo.getCronJob()) {
	
		newTrigger = scheduleCreator.createCronTrigger(
		        jobInfo.getJobName(), 
		        new Date(), 
		        jobInfo.getCronExpression(), 
		        simpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
	} else {
	
		newTrigger = scheduleCreator.createSimpleTrigger(
		        jobInfo.getJobName(), 
		        new Date(), 
		        jobInfo.getRepeatTime(),
			    SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
	}
	try {
		schedulerFactoryBean.getScheduler().rescheduleJob(TriggerKey.triggerKey(jobInfo.getJobName()), newTrigger);
		jobInfo.setJobStatus("EDITED & SCHEDULED");
		schedulerRepository.save(jobInfo);
		log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " updated and scheduled.");
	} catch (SchedulerException e) {
		log.error(e.getMessage(), e);
	}
}

运行一次 Quartz 作业

有时您想在临时情况下触发触发器。您可能还想在提交时间表之前解雇一份工作以测试它是否工作正常。

我们可以使用triggerJob()方法立即触发它,而无需等待预定的 cron 或时间。这允许我们创建一个测试热键:

public boolean startJobNow(SchedulerJobInfo jobInfo) {
    try {
        SchedulerJobInfo getJobInfo = schedulerRepository.findByJobName(jobInfo.getJobName());
        getJobInfo.setJobStatus("SCHEDULED & STARTED");
        schedulerRepository.save(getJobInfo);
        schedulerFactoryBean.getScheduler().triggerJob(new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
        log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " scheduled and started now.");
        return true;
    } catch (SchedulerException e) {
        log.error("Failed to start new job - {}", jobInfo.getJobName(), e);
        return false;
    }
}

暂停 Quartz 作业

如果您想暂停正在运行的Cron Job 或 Simple Job,我们可以使用该pauseJob()方法,该方法将暂停一个作业,直到您恢复它:

public boolean pauseJob(SchedulerJobInfo jobInfo) {
    try {
        SchedulerJobInfo getJobInfo = schedulerRepository.findByJobName(jobInfo.getJobName());
     	getJobInfo.setJobStatus("PAUSED");
        schedulerRepository.save(getJobInfo);
        schedulerFactoryBean.getScheduler().pauseJob(new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
      log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " paused.");
        return true;
    } catch (SchedulerException e) {
        log.error("Failed to pause job - {}", jobInfo.getJobName(), e);
        return false;
    }
}

恢复 Quartz 工作

resumeJob()自然,我们可以通过简单地使用以下方法来恢复暂停的作业:

public boolean resumeJob(SchedulerJobInfo jobInfo) {
    try {
      SchedulerJobInfo getJobInfo = schedulerRepository.findByJobName(jobInfo.getJobName());
      getJobInfo.setJobStatus("RESUMED");
      schedulerRepository.save(getJobInfo);
      schedulerFactoryBean.getScheduler().resumeJob(new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
      log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " resumed.");
      return true;
    } catch (SchedulerException e) {
      log.error("Failed to resume job - {}", jobInfo.getJobName(), e);
      return false;
    }
}

删除 Quartz 作业

最后,我们可以通过调用该deleteJob()方法删除一个作业:

public boolean deleteJob(SchedulerJobInfo jobInfo) {
    try {
        SchedulerJobInfo getJobInfo = schedulerRepository.findByJobName(jobInfo.getJobName());
        schedulerRepository.delete(getJobInfo);
        log.info(">>>>> jobName = [" + jobInfo.getJobName() + "]" + " deleted.");
        return schedulerFactoryBean.getScheduler().deleteJob(new JobKey(jobInfo.getJobName(), jobInfo.getJobGroup()));
    } catch (SchedulerException e) {
      log.error("Failed to delete job - {}", jobInfo.getJobName(), e);
      return false;
    }
}

Quartz 管理控制台用户界面

现在,我们已经拥有了将Quartz 管理控制台与我们可以测试功能的 Web 应用程序用户界面结合在一起所需的所有功能。

注意:此应用程序的 UI 用于演示调度程序的生命周期管理,并且 UI 比后端多变。因此,我们不会过多关注其实施。但是,您可以在我们的GitHub 存储库中访问前端的完整代码。

任何触发我们之前定义的方法的 REST API 都可以正常工作。我们的实现使用 Thymeleaf 作为渲染引擎。

如果您想了解有关 Thymeleaf 的更多信息,请阅读Java 和 Spring 中的 Thymeleaf 入门。

如果您想了解有关构建 REST API 的更多信息,请阅读我们的使用 Spring Boot 构建 REST API 指南。

运行应用程序后,让我们导航到http://localhost:8080/index,也可以查看仪表板。

首先,让我们选择创建按钮来创建一个新作业。它将打开一个弹出窗口并提示我们填写作业详细信息。

让我们创建一个 Cron Job 和一个 Simple Job:

使用 Spring Boot 的 Quartz 指南

使用 Spring Boot 的 Quartz 指南

我们可以在 JobStore 中看到所有添加的作业:

使用 Spring Boot 的 Quartz 指南

您还可以查看作业日志 - 当作业被触发时,根据其触发条件一一触发。

结论

在本指南中,我们介绍了 Quartz - 一个强大的调度程序并将其实现到 Spring Boot 应用程序中。

我们通过简单 UI 中的演示研究了 Quartz 调度程序的整体生命周期管理。我们使用了一些简约的作业,但您可以尝试定义复杂的作业,例如触发电子邮件警报或异步消息处理等,并使用 Quartz 进行调度。

与往常一样,您可以在GitHub 上找到完整的源代码。

github: https://github.com/StackAbuse/spring-boot-quartz

https://stackabuse.com/guide-to-quartz-with-spring-boot-job-scheduling-and-automation/

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章