Spring框架集成

前面介绍的内容我们都是在普通Java工程中使用Quartz框架。在Spring工程中,Spring框架为Quartz提供了一些封装,方便我们使用。这里我们介绍如何将Quartz集成到Spring中。

Quartz和Spring的@Scheduled对比

我们知道Spring本身提供了一种基于JDK的@Scheduled计划任务功能,和Quartz相比,@Scheduled的优点是使用非常方便,直接使用注解标注SpringBean的方法即可实现计划任务。当然缺点也很明显,它的功能太过简略,它不支持分布式,而且调度信息也不能持久化。而Quartz支持分布式锁和调度信息存储,任务、触发器都可以动态注册、删除以及进行启停操作,显然其功能比@Scheduled强大很多,不过缺点则是用起来比较麻烦。

Spring工程集成Quartz

Spring框架对Quartz进行了封装,默认集成到了spring-context包中,除了Quartz框架本身,不需要再额外引入什么依赖。

Job

Spring提供了JobDetailFactoryBean,它用于封装JobDetail并自动注册到Scheduler,下面是一个例子。

package com.gacfox.cron;

import org.quartz.*;
import org.springframework.scheduling.quartz.QuartzJobBean;

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class DemoJob extends QuartzJobBean {

    private Integer count;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        count++;
        context.getJobDetail().getJobDataMap().put("count", count);
        System.out.println("Job参数:已执行次数 count [" + count + "]");
    }

    public void setCount(Integer count) {
        this.count = count;
    }
}

上面代码没有什么特别的,就是我们之前章节编写的一个有状态Job。但要注意,这里我们继承的是Spring提供的QuartzJobBean基类,这一点和之前不同,其余方法参数等都与之前一致。

<!-- 配置Job -->
<bean id="demoJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="com.gacfox.cron.DemoJob"/>
    <property name="jobDataAsMap">
        <map>
            <entry key="count" value="0"/>
        </map>
    </property>
</bean>

Spring配置文件中,我们使用JobDetailFactoryBean装配了demoJob这个Bean,其API和之前我们使用Quartz中的JobDetail是类似的。这里我们指定了Job的类名以及参数。

Trigger

Spring和Quartz原版的封装层次有些不同,Spring是将Job封装到Trigger里,其他参数均一致。

<!-- 为demoJob配置Trigger -->
<bean id="demoJobCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="demoJob"/>
    <property name="cronExpression" value="0/1 * * * * ?"/>
</bean>

Scheduler

下面代码我们通过Spring提供的SchedulerFactoryBean来创建Scheduler,参数中我们指定了Quartz配置文件位置,以及之前我们创建的所有Trigger。quartz.properties配置文件的内容可以参考之前的例子。

<!-- 配置Scheduler -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="configLocation" value="classpath:quartz.properties" />
    <property name="triggers">
        <list>
            <ref bean="demoJobCronTrigger"/>
        </list>
    </property>
</bean>

对于JDBC使用的数据源,我们可以单独使用Quartz默认引入的c3p0,这样便于将Quartz和业务数据划分到两个独立的数据库中互不影响;也可以将其和工程的数据源配置成一个。

SpringBoot工程集成Quartz

如果使用SpringBoot搭建工程,在配置上有一些区别,SpringBoot工程中我们直接引入Quartz的起步依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

application.properties配置文件中,我们先配置了SpringBoot工程默认使用的数据源,在之后的Quartz配置中我们没有再额外指定数据源了,此时Quartz会自动使用工程默认的数据源。

application.properties

spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=1
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.idle-timeout=60000
spring.datasource.url=jdbc:mysql://127.0.0.1/demoquartz?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root

spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema=never
spring.quartz.properties.org.quartz.scheduler.instanceName=QuartzScheduler
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
spring.quartz.properties.org.quartz.threadPool.threadCount=10
spring.quartz.properties.org.quartz.threadPool.threadPriority=5
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.org.quartz.jobStore.isClustered=true

spring.quartz.properties前缀的配置中可编写的配置内容和之前quartz.properties配置文件中的内容一致,我们在这些配置中指定Quartz的线程池配置、使用集群模式等信息。

QuartzConfig.java

package com.gacfox.bootquartz.config;

import com.gacfox.bootquartz.crontab.DemoJob;
import org.quartz.JobDetail;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Configuration
public class QuartzConfig {
    @Bean
    public JobDetailFactoryBean demoJobDetail() {
        JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
        jobDetailFactoryBean.setJobClass(DemoJob.class);
        Map<String, Integer> dataMap = new ConcurrentHashMap<>();
        dataMap.put("count", 0);
        jobDetailFactoryBean.setJobDataAsMap(dataMap);
        jobDetailFactoryBean.setDurability(true);
        return jobDetailFactoryBean;
    }

    @Bean
    public CronTriggerFactoryBean demoJobTrigger(JobDetail demoJobDetail) {
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        cronTriggerFactoryBean.setJobDetail(demoJobDetail);
        cronTriggerFactoryBean.setCronExpression("0/1 * * * * ?");
        return cronTriggerFactoryBean;
    }
}

QuartzConfig配置类的作用和前面XML配置中的一致,其中我们配置了JobDetailJobTrigger这两个Bean,JobDetail中指定了Job的实现类。DemoJob类的内容和前面完全相同,这里就不重复粘贴了。

如果希望Quartz使用单独的数据库,可以在SpringBoot中使用@QuartzDataSource注解标注数据源Bean的配置类,这样就可以实现为Quartz单独指定数据源了。

 @Bean
 @QuartzDataSource
 @ConfigurationProperties(prefix = "spring.datasource.qrtzDataSource")
 public DataSource quartzDataSource(){
     // ... 创建数据源
 }
作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap