小强哥博客

小强哥,小强哥博客,技术大咖

subic项目总结(四)-springboot中配置quartz

Quartz是一个基于mysql数据库的分布式调度框架,最近项目上在使用,这里整理下如何在SpringBoot中使用Quartz。

项目基于SpringBoot+Maven构建,如下pom.xml,其中Quartz的版本是2.2.1版本。对应的msyql数据库在http://download.csdn.net/download/minicto/9949099 可以下载到。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.eju.ess</groupId>
	<artifactId>subic</artifactId>
	<version>0.0.1</version>
	<packaging>jar</packaging>


	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.4.RELEASE</version>
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<!-- spring plateform -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-logging</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-log4j2</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>2.2.1</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
	</dependencies>
</project>

创建一个JobFactory类,该类的作用是可以在Job接口的实现类中使用Spring注入功能。如果不需要在Job接口的实现类中使用Sprig注入功能可以不使用。这背后的原因就是每次执行的时候,Job接口实现类都是重新实例化的。如下代码,

package com.eju.ess.common.config.quartzcfg;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

@Component
public class JobFactory extends AdaptableJobFactory{
	@Autowired  
    private AutowireCapableBeanFactory capableBeanFactory;  
  
    @Override  
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {  
        //调用父类的方法  
        Object jobInstance = super.createJobInstance(bundle);  
        //进行注入  
        capableBeanFactory.autowireBean(jobInstance);  
        return jobInstance;  
    } 
}

创建Scheduler工厂对象,该对象的最大的好处就是可以直接配置Spring的DataSource,如果想自己配置数据源可以参考 http://xiaoqiangge.com/aritcle/1503632623812.html

package com.eju.ess.common.config.quartzcfg;

import java.io.IOException;

import javax.sql.DataSource;

import org.quartz.JobDetail;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

@Configuration
public class SchedulerConfiguration {
	@Bean
	public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource,JobFactory jobFactory) throws IOException {
		SchedulerFactoryBean factory = new SchedulerFactoryBean();
		factory.setOverwriteExistingJobs(true);
		factory.setDataSource(dataSource);
		factory.setJobFactory(jobFactory);
		PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
		propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
		propertiesFactoryBean.afterPropertiesSet();
		factory.setQuartzProperties(propertiesFactoryBean.getObject());
		return factory;
	}
}

在创建SchedulerFactoryBean对象的时候,需要指定一个quartz.properties文件,如下,

org.quartz.scheduler.instanceName=subic
org.quartz.scheduler.instanceId=AUTO
org.quartz.threadPool.threadCount=10
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix=QRTZ_
# 设置为 true 打开集群特性。如果你有多个 Quartz 实例在用同一套数据库时,这个属性就必须设置为 true。
org.quartz.jobStore.isClustered=true
# 用于实例报告给集群中的其他实例。这会影响到侦测失败实例的敏捷度。它只用于设置了 isClustered 为 true 的时候。
org.quartz.jobStore.clusterCheckinInterval=1000
#这个时间大于10000(10秒)会导致MISFIRE_INSTRUCTION_DO_NOTHING不起作用。 
org.quartz.jobStore.misfireThreshold = 1000

创建一个计划任务代码,如下完整代码,创建计划任务有两部分,第一部分是创建一个JobDetail,其中主要就是需要指定一个job的实现类,在我的这个sample中我指定的是JobService.class这个类;第二部分是创建一个Trigger,其中主要就是需要指定一个CronExpression表达式。

try {
			Scheduler scheduler = schedulerFactoryBean.getScheduler();
			JobDetail job = JobBuilder.newJob(JobService.class)
					.build();
			CronTrigger trigger = TriggerBuilder.newTrigger()
					.withSchedule(CronScheduleBuilder.cronSchedule("CronExpression").withMisfireHandlingInstructionDoNothing())
					.build();
			scheduler.scheduleJob(job, trigger);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}

JobDetail的执行类如下,该类需要实现Job接口,并实现execute方法,每次时间到了以后就会调用execute处理自己的业务逻辑。

package com.eju.ess.service.job;

import lombok.extern.slf4j.Slf4j;


import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class JobService implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
    	// 执行逻辑
    }
}