Quartz

quartz原理
quartz

Quartz调度核心元素

  • Scheduler:任务调度器,是实际执行任务调度的控制器。在spring中通过SchedulerFactoryBean封装起来。

  • Trigger:触发器,用于定义任务调度的时间规则,有SimpleTrigger,CronTrigger,DateIntervalTrigger和NthIncludedDayTrigger,其中CronTrigger用的比较多,本文主要介绍这种方式。CronTrigger在spring中封装在CronTriggerFactoryBean中。
    Calendar:它是一些日历特定时间点的集合。一个trigger可以包含多个Calendar,以便排除或包含某些时间点。

  • JobDetail:用来描述Job实现类及其它相关的静态信息,如Job名字、关联监听器等信息。在spring中有JobDetailFactoryBean和 MethodInvokingJobDetailFactoryBean两种实现,如果任务调度只需要执行某个类的某个方法,就可以通过MethodInvokingJobDetailFactoryBean来调用。

  • Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中。实现Job接口的任务,默认是无状态的,若要将Job设置成有状态的,在quartz中是给实现的Job添加@DisallowConcurrentExecution注解(以前是实现StatefulJob接口,现在已被Deprecated),在与spring结合中可以在spring配置文件的job detail中配置concurrent参数。

Quartz 集群

quartz集群是通过数据库表来感知其他的应用的,各个节点之间并没有直接的通信。只有使用持久的JobStore才能完成Quartz集群。
数据库表:有11张表,表信息如下

Quartz_第1张图片
image.png

Quartz_第2张图片
image.png

QRTZ_LOCKS就是Quartz集群实现同步机制的行锁表,包括以下几个锁:CALENDAR_ACCESS 、JOB_ACCESS、MISFIRE_ACCESS 、STATE_ACCESS 、TRIGGER_ACCESS

数据存储

Quartz 中的 trigger 和 job 需要存储下来才能被使用。Quartz 中有两种存储方式:RAMJobStore, JobStoreSupport,其中 RAMJobStore 是将 trigger 和 job 存储在内存中,而 JobStoreSupport 是基于 jdbc 将 trigger 和 job 存储到数据库中。RAMJobStore 的存取速度非常快,但是由于其在系统被停止后所有的数据都会丢失,所以在通常应用中,都是使用 JobStoreSupport。

在 Quartz 中,JobStoreSupport 使用一个驱动代理来操作 trigger 和 job 的数据存储:StdJDBCDelegate。StdJDBCDelegate 实现了大部分基于标准 JDBC 的功能接口,但是对于各种数据库来说,需要根据其具体实现的特点做某些特殊处理,因此各种数据库需要扩展 StdJDBCDelegate 以实现这些特殊处理。

在Hap中使用的就是JobStoreSupport持久化存储,下面简单介绍一下常见几张表对应的关系:

Quartz_第3张图片
image.png

这个界面的数据,存放在 qrtz_job_details 表中,但是这里还是有一些需要注意的地方。并不是所有的参数都在这个表中,比如 上次执行时间、下次执行时间、corn表达式等信息,实际上是存在别的表中,这个视 任务的类型来判断。当简单任务的时候,存在 qrtz_simple_triggers 表中;当 corn 任务的时候,存在 qrtz_triggers 表中。


Quartz_第4张图片
image.png

不知道大家有没有想过这个问题,任务中的参数是放在哪里?我一开始以为会放到一张表里,最后发现参数其实是存在 qrtz_job_details 表里的一个字段上的。

image.png

是一个blob类型。

其实Hap在Job这一块封装的东西不算是很多。我们在开发时主要用到的就是一个 AbstractJob 类,之后会介绍到。还有就是任务运行记录,在Hap中是将任务执行记录存在 sys_job_running_info 表中,其实也是在 quratz 的监听器基础上做到的,之后会有介绍。

配置

applicationContext-job.xml






    
    
        
        
        
        
            
        
        
        
    

quartz.properties

#============================================================================
# Configure Scheduler
#============================================================================

org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
#org.quartz.scheduler.rmi.export = false
#org.quartz.scheduler.rmi.proxy = false
#org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
org.quartz.scheduler.skipUpdateCheck = true


#============================================================================
# Configure ThreadPool
#============================================================================
#org.quartz.threadPooln.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
#org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true


#============================================================================
# Configure JobStore
#============================================================================
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.maxMisfiresToHandleAtATime=1

#org.quartz.jobStore.misfireThreshold = 60000
#org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#org.quartz.scheduler.classLoadHelper.class=org.quartz.simpl.CascadingClassLoadHelper
#org.quartz.jobStore.useProperties = true

#============================================================================
# Microsoft SQL Server
#============================================================================
#org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate
#org.quartz.jobStore.selectWithLockSQL=SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?




#============================================================================
# Configure Plugins 
#============================================================================
#org.quartz.plugin.triggHistory.class=org.quartz.plugins.history.LoggingJobHistoryPlugin
org.quartz.plugin.runningListener.class=com.hand.hap.job.plugin.RunningListenerPlugin
org.quartz.plugin.runningListener.LogRunningInfo=true
org.quartz.plugin.runningListener.mailTemplate=email_job_running_notification

quratz默认是使用RAMJobStore存储,这是将信息存储再内存中,这种方式有一个好处就是速度快,单缺点也很明显:不能持久化存储,如果系统出问题 就得从头开始,所以在项目上我没一般是采用持久化存储这种方式。如果需要数据库持久化存储,一般需要在quartz.properties配置文件中将存储方式改成jdbcjobstore,例如:

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

但在Hap中并没有直接在quartz.properties配置文件中定义数据库得连接方式,而是在 applicationContext-job.xml 配置文件中将数据源注入进去了。

    
    
        
        
        
        
            
        
        
        
    

因为spring 不能在quartz中注入bean的,所以这里自定义了 一个 jobFactory

package com.hand.hap.job;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

/**
 * 支持 AutoWired.
 * 
 */
public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
    private transient AutowireCapableBeanFactory beanFactory;

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

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

applicationContextSchedulerContextKey 是 org.springframework.scheduling.quartz.SchedulerFactoryBean这个类中把spring上下 文以key/value的方式存放在了quartz的上下文中了,可以用applicationContextSchedulerContextKey所定义的key得到对应的spring上下文。

Listeners

这是Hap中Job模块的关键部分。Listeners是您创建的对象,用于根据调度程序中发生的事件执行操作。

TriggerListeners和JobListeners

您可能猜到,TriggerListeners接收到与触发器(trigger)相关的事件,JobListeners 接收与jobs相关的事件。
与触发相关的事件包括:触发器触发,触发失灵(在本文档的“触发器”部分中讨论),并触发完成(触发器关闭的作业完成)。
org.quartz.TriggerListener接口

public interface TriggerListener {

    public String getName();

    public void triggerFired(Trigger trigger, JobExecutionContext context);

    public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);

    public void triggerMisfired(Trigger trigger);

    public void triggerComplete(Trigger trigger, JobExecutionContext context,
            int triggerInstructionCode);
}

job相关事件包括:job即将执行的通知,以及job完成执行时的通知。
org.quartz.JobListener接口

public interface JobListener {

    public String getName();

    public void jobToBeExecuted(JobExecutionContext context);

    public void jobExecutionVetoed(JobExecutionContext context);

    public void jobWasExecuted(JobExecutionContext context,
            JobExecutionException jobException);

}

使用TriggerListeners和JobListeners

要创建一个listener,只需创建一个实现org.quartz.TriggerListener和/或org.quartz.JobListener接口的对象。然后,listener在运行时会向调度程序注册,并且必须给出一个名称(或者,他们必须通过他们的getName()方法来宣传自己的名字)。
为了方便起见,实现这些接口,您的类也可以扩展JobListenerSupport类或TriggerListenerSupport类,并且只需覆盖您感兴趣的事件。
listener与调度程序的ListenerManager一起注册,并配有描述listener希望接收事件的job/触发器的Matcher。
Listener在运行时间内与调度程序一起注册,并且不与jobs和触发器一起存储在JobStore中。这是因为听众通常是与应用程序的集成点。因此,每次运行应用程序时,都需要重新注册该调度程序。

添加对特定job感兴趣的JobListener

scheduler.getListenerManager().addJobListener(myJobListener,KeyMatcher.jobKeyEquals(new JobKey(“myJobName”,“myJobGroup”)));

这将上面的例子变成这样:

scheduler.getListenerManager().addJobListener(myJobListener, jobKeyEquals(jobKey("myJobName", "myJobGroup")));

添加对特定组的所有job感兴趣的JobListener:

scheduler.getListenerManager().addJobListener(myJobListener, jobGroupEquals("myJobGroup"));

添加对两个特定组的所有job感兴趣的JobListener:

scheduler.getListenerManager().addJobListener(myJobListener, or(jobGroupEquals("myJobGroup"), jobGroupEquals("yourGroup")));

添加对所有job感兴趣的JobListener:

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

注册TriggerListeners的工作原理相同。

Quartz的大多数用户并不使用Listeners,但是当应用程序需求创建需要事件通知时不需要Job本身就必须明确地通知应用程序,这些用户就很方便。

SchedulerListeners

SchedulerListeners非常类似于TriggerListeners和JobListeners,除了它们在Scheduler本身中接收到事件的通知 (不一定与特定触发器(trigger)或job相关的事件)
与计划程序相关的事件包括:添加job/触发器,删除job/触发器,调度程序中的严重错误,关闭调度程序的通知等。

org.quartz.SchedulerListener接口:

public interface SchedulerListener {

    public void jobScheduled(Trigger trigger);

    public void jobUnscheduled(String triggerName, String triggerGroup);

    public void triggerFinalized(Trigger trigger);

    public void triggersPaused(String triggerName, String triggerGroup);

    public void triggersResumed(String triggerName, String triggerGroup);

    public void jobsPaused(String jobName, String jobGroup);

    public void jobsResumed(String jobName, String jobGroup);

    public void schedulerError(String msg, SchedulerException cause);

    public void schedulerStarted();

    public void schedulerInStandbyMode();

    public void schedulerShutdown();

    public void schedulingDataCleared();
}

SchedulerListeners注册到调度程序的ListenerManager。SchedulerListeners几乎可以实现任何实现org.quartz.SchedulerListener接口的对象。

添加SchedulerListener:

scheduler.getListenerManager().addSchedulerListener(mySchedListener);

删除SchedulerListener:

scheduler.getListenerManager().removeSchedulerListener(mySchedListener);

Hap中的Listener

Hap中得Listener如下:

Quartz_第5张图片
image.png

主要包括三类:JobListener、TriggerListener、SchedulerListener ;

前面那三个 Default开头得Listener,没有什么实质性得内容,只是分别单纯得实现了 JobListener、TriggerListener、SchedulerListener 这个三个接口,这样接下来得哪几个Listener分别继承Default开头得那几个Listener,就不用是实现JobListener、TriggerListener、SchedulerListener 接口中所有得方法了。这其实就是适配器模式中的 接口适配器模式。至于这几个适配器里面的逻辑,就不过多说明了。可以简单看看 SchedulerRunningListener:

/*
 * #{copyright}#
 */
package com.hand.hap.job.listener;

import com.hand.hap.job.service.IJobRunningInfoService;
import org.quartz.JobKey;
import org.quartz.listeners.SchedulerListenerSupport;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;

import com.hand.hap.job.dto.JobRunningInfoDto;

/**
 * @author shiliyan
 *
 */
public class SchedulerRunningListener extends SchedulerListenerSupport {

    private static final String JOB_INFO_HAS_DELETED = "Job Info [{}.{}] has deleted.";
    private static final String JOB_WAS_DELETED_FROM_SCHEDULER = "Job [{}.{}] was deleted from Scheduler.";
    private final ApplicationContext applicationContext;

    public SchedulerRunningListener(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /*
     * (non-Javadoc)
     * 
     * @see DefaultSchedulerListener#jobDeleted(org.quartz.JobKey)
     */
    @Override
    public void jobDeleted(JobKey jobKey) {
        JobRunningInfoDto dto = new JobRunningInfoDto();
        String group = jobKey.getGroup();
        String name = jobKey.getName();
        logInfo(JOB_WAS_DELETED_FROM_SCHEDULER, group, name);
        dto.setJobName(name);
        dto.setJobGroup(group);
        deleteJobInfo(dto);
        logInfo(JOB_INFO_HAS_DELETED, group, name);
    }

    private void deleteJobInfo(JobRunningInfoDto jobCreateDto) {
        IJobRunningInfoService jobRunningInfoService = applicationContext.getBean(IJobRunningInfoService.class);
        jobRunningInfoService.delete(jobCreateDto);
    }

    protected void logInfo(String info, Object... para) {
        if (getLog().isInfoEnabled()) {
            getLog().info(info, para);
        }
    }

    protected void logInfo(String info) {
        if (getLog().isInfoEnabled()) {
            getLog().info(info);
        }
    }

}

有个 jobDeleted 方法,根据代码可以看出,在删除job的时候,会删除 sys_job_running_info 表中对应Job的执行记录。

插件SchedulerPlugin

在Hap 中的 quartz.properties 配置文件中,有这样一行配置

org.quartz.plugin.runningListener.class=com.hand.hap.job.plugin.RunningListenerPlugin

这其实就是quartz的插件功能。
在上面我没已经提到了Hap中对应Listener类型分别定义了几个Listener,但是发现还少了点什么。并没有在哪个地方看到JobRunningListener添加了需要监听的Job。其实这些动作都在 RunningListenerPlugin 中。

image.png

DefaultSchedulerPlugin 实现了 SchedulerPlugin, 没什么实质的内容

Quartz_第6张图片
image.png

RunningListenerPlugin 继承了 DefaultSchedulerPlugin,并重写了 start 方法,然后将所有 Job和 JobRunningListener关联起来

Quartz_第7张图片
image.png

至此,有关于Hap中Job的内容到此结束。下一章节将介绍 quartz 在 soringboot2 中的应用。

整合Springboot

上一章节介绍了Quartz在Hap中的应用(其实就是在spring 中的应用)。本章节介绍 Quartz 在 springboot2中的应用。

添加依赖

        
        
            org.quartz-scheduler
            quartz
        
        
        
            org.quartz-scheduler
            quartz-jobs
        

有可莪能会报一个 c3p0的错误,这时候需要添加一个依赖

        
        
            com.mchange
            c3p0
            0.9.5.2
        

配置

///QuartzConfigure

package com.hand.sxy.config;

import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

import javax.sql.DataSource;


/**
 * @author pavan.solapure
 */

@Configuration
@EnableScheduling
public class QuartzConfigure {


    /**
     * 继承org.springframework.scheduling.quartz.SpringBeanJobFactory
     * 实现任务实例化方式
     */
    public static class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
            ApplicationContextAware {

        private transient AutowireCapableBeanFactory beanFactory;

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

        /**
         * 将job实例交给spring ioc托管
         * 我们在job实例实现类内可以直接使用spring注入的调用被spring ioc管理的实例
         *
         * @param bundle
         * @return
         * @throws Exception
         */
        @Override
        protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
            final Object job = super.createJobInstance(bundle);
            /**
             * 将job实例交付给spring ioc
             */
            beanFactory.autowireBean(job);
            return job;
        }
    }

    /**
     * 配置任务工厂实例
     *
     * @param applicationContext spring上下文实例
     * @return
     */
    @Bean
    public JobFactory jobFactory(ApplicationContext applicationContext) {
        /**
         * 采用自定义任务工厂 整合spring实例来完成构建任务
         * see {@link AutowiringSpringBeanJobFactory}
         */
        AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
        jobFactory.setApplicationContext(applicationContext);
        return jobFactory;
    }

    /**
     * 配置任务调度器
     * 使用项目数据源作为quartz数据源
     *
     * @param jobFactory 自定义配置任务工厂
     * @param dataSource 数据源实例
     * @return
     * @throws Exception
     */
    @Bean(destroyMethod = "destroy", autowire = Autowire.NO)
    public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, DataSource dataSource) throws Exception {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        //将spring管理job自定义工厂交由调度器维护
        schedulerFactoryBean.setJobFactory(jobFactory);
        //设置覆盖已存在的任务
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        //项目启动完成后,等待2秒后开始执行调度器初始化
        schedulerFactoryBean.setStartupDelay(2);
        //设置调度器自动运行
        schedulerFactoryBean.setAutoStartup(true);
        //设置数据源,使用与项目统一数据源
        schedulerFactoryBean.setDataSource(dataSource);
        //设置上下文spring bean name
        schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
        //设置配置文件位置
        schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));
        return schedulerFactoryBean;
    }
}

//quartz.properties

# 固定前缀org.quartz
# 主要分为scheduler、threadPool、jobStore、plugin等部分
#
#
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false

# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool

# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount = 5

# 优先级
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

org.quartz.jobStore.misfireThreshold = 5000

# 默认存储在内存中
#org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

#持久化
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_

org.quartz.jobStore.dataSource = qzDS

org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver

org.quartz.dataSource.qzDS.URL = jdbc:mysql://localhost:3306/vue?characterEncoding=utf8&autoReconnect=true&useSSL=false

org.quartz.dataSource.qzDS.user = root

org.quartz.dataSource.qzDS.password = root

org.quartz.dataSource.qzDS.maxConnections = 10

使用

//BasalJob

package com.hand.sxy.job;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * @author spilledyear
 */
public interface BasalJob extends Job {

    /**
     * Job执行入口
     *
     * @param context
     * @throws JobExecutionException
     */
    @Override
    void execute(JobExecutionContext context) throws JobExecutionException;
}

//HelloJob

package com.hand.sxy.job.example;

import com.hand.sxy.job.BasalJob;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

/**
 * @author spilledyear
 */
public class HelloJob implements BasalJob {

    private static Logger logger = LoggerFactory.getLogger(HelloJob.class);

    public HelloJob() {

    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        logger.info("Hello Job执行时间: " + new Date());

    }
}  

//JobController

package com.hand.sxy.job.controller;

import com.hand.sxy.job.BasalJob;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
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.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


/**
 * @author spilledyear
 */
@RestController
@RequestMapping(value = "/job")
public class JobController {
    private static Logger log = LoggerFactory.getLogger(JobController.class);

    @Autowired
    private Scheduler scheduler;


    @RequestMapping(value = "/addjob", method = RequestMethod.GET)
    public void addjob(@RequestParam(value = "jobGroup") String jobGroup,
                       @RequestParam(value = "jobName") String jobName,
                       @RequestParam(value = "jobClassName") String jobClassName,
                       @RequestParam(value = "cronExpression") String cronExpression) throws Exception {
        addJob(jobGroup, jobName, jobClassName, cronExpression);
    }

    public void addJob(String jobGroup, String jobName, String jobClassName, String cronExpression) throws Exception {

        // 启动调度器
        scheduler.start();

        //构建job信息
        JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobGroup, jobName).build();

        //表达式调度构建器(即任务执行的时间)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

        //按新的cronExpression表达式构建一个新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobGroup, jobName)
                .withSchedule(scheduleBuilder).build();

        try {
            scheduler.scheduleJob(jobDetail, trigger);

        } catch (SchedulerException e) {
            System.out.println("创建定时任务失败" + e);
            throw new Exception("创建定时任务失败");
        }
    }
.....
}

在前端请求 /job/addJob接口(其实已经集成到了那两个前后端分离的应用中,前端可视化管理Job)

后台日志

Quartz_第8张图片
image.png

数据库数据

Quartz_第9张图片
image.png

Quartz_第10张图片
image.png

前端可视化管理


Quartz_第11张图片

你可能感兴趣的:(Quartz)