之前有用到过Quartz这个调度框架,这个框架一般是用来做定时业务处理的。比如定时每天的报表导出、定时数据采集等,只要是定时自动调度的业务都能交给它去完成,并且能和Spring MVC搭配使用,配置也很简洁,使用起来也很简单。在配置时也遇到了两种不同的配置,所出现的情况也有差别。
配置一:这种配置方式能够使用Spring的注解来完成依赖注入(这是我实际遇到的情况,不一定是必然的,有可能是因为Spring的配置差别的原因导致它能使用依赖注入,但配置方式上确实不同)。
<?xml version="1.0" encoding="UTF-8"?>
<beans default-lazy-init="true"
xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!-- Quartz调度工厂:
将配置完成的JobTrigger放入调度工厂中实现调度
-->
<bean id="schedulerBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
<property name="triggers">
<list>
<ref bean="dailyQuartzJobTrigger"/>
<ref bean="monitorQuartzJobTrigger"/>
</list>
</property>
</bean>
<!-- 编写任务的类 -->
<bean id="jobDetailBean" class="com.tisson.omp.quartz.JobDetailBean" />
<!-- 任务1
targetObject:调用的类
targetMethod:执行的任务内容,即类中的方法名
-->
<bean id="dailyQuartzJobMethod" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="jobDetailBean" />
</property>
<property name="targetMethod">
<value>dailyQuartzJob</value>
</property>
</bean>
<!-- 设置调度规则
0 20 16 * * ?:代表每天下午4点20分时调度一次这个方法
-->
<bean id="dailyQuartzJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="dailyQuartzJobMethod" />
<property name="cronExpression" value="0 20 16 * * ?" />
</bean>
<!-- 1end -->
<!-- 任务2 -->
<bean id="monitorQuartzJobMethod" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="jobDetailBean" />
</property>
<property name="targetMethod">
<value>monitorQuartzJob</value>
</property>
</bean>
<!-- 设置调度规则
0 0/5 * * * ?:代表每5分钟调度一次这个方法
-->
<bean id="monitorQuartzJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="monitorQuartzJobMethod" />
<property name="cronExpression" value="0 0/5 * * * ?" />
</bean>
<!-- 2end -->
</beans>
配置二:这种配置方式不能使用Spring的注解来完成依赖注入(这是我实际遇到的情况,不一定是必然的,有可能是因为Spring的配置差别的原因导致它不能使用依赖注入,但配置方式上确实不同)。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd"
default-autowire="byName" default-lazy-init="false">
<!-- 数据源bean注入 -->
<bean id="Source" class="org.quartz.JobDataMap">
<constructor-arg>
<map>
<entry key="本地数据库1" value-ref="test1Service" /> <!-- value-ref注入的是bean,value注入的是字符串 -->
<entry key="本地数据库2" value-ref="test22Service" />
<entry key="Linux" value="linux" />
</map>
</constructor-arg>
</bean>
<!-- 作业bean命名要与SCHEDULE_ID一致 -->
<!-- 任务1配置 -->
<bean id="health_1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="org.drh.wisdom.quartz.JobTask" />
<property name="jobDataMap">
<map>
<entry key="SCHEDULE_ID" value="1" />
<entry key="SOURCE" value-ref="Source" />
</map>
</property>
</bean>
<!-- 对应SCHEDULE_ID进行命名 -->
<bean id="CronTrigger_health_1" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="health_1" />
<property name="cronExpression" value="0 0/15 * * * ?" />
</bean>
<!-- 配置结束 -->
<!-- 任务2配置 -->
<bean id="scene_1"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="org.drh.wisdom.quartz.JobTask2" />
<property name="jobDataMap">
<map>
<entry key="SCHEDULE_ID" value="1" />
<entry key="SOURCE" value-ref="Source" />
</map>
</property>
</bean>
<bean id="CronTrigger_scene_1" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="scene_1" />
<property name="cronExpression" value="0 0/15 * * * ?" />
</bean>
<!-- 配置结束 -->
<!-- 总配置 -->
<!-- 增加线程池用于作业调度 -->
<bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="500" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="CronTrigger_health_1" />
<ref bean="CronTrigger_scene_1" />
</list>
</property>
<property name="taskExecutor" ref="executor" />
</bean>
<!-- 总配置结束 -->
</beans>
因为无法使用注解注入service,所以使用了框架中提供的jobDataMap来将service注入到job类里。因此id为Source中的service都是Spring中已经控制反转了的service。job类中获取通过map传递service的代码如下:
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.drh.common.utils.DateUtil;
import org.drh.wisdom.data.service.INewgzcrm2Service;
import org.drh.wisdom.data.service.IZhptdbService;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
public class JobTask extends QuartzJobBean {
private static final Logger logger = LoggerFactory.getLogger(JobTask.class);
// 获取指标配置
private static Map<String, List> kpiMap;
// 轮询规则
private static String scheduleId;
// 批次标识
private static long batchId;
// 数据源服务
private static IZhptdbService test1Service;
private static INewgzcrm2Service test2Service;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
/**
下面是获取xml中配置的,封装在map中的value。
因为先在Source中放入了service的bean,然后又将Source放入任务1的map中,
所以在取service时需要先获取任务1的map中key为SOURCE的value,这个value
是一个新map,即Source,再根据service的key获取service的bean,然后赋值
给this.service就行了。
**/
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
JobDataMap sourceMap = (JobDataMap) jobDataMap.get("SOURCE");
// 获取当前轮询规则标识
scheduleId = (String) jobDataMap.get("SCHEDULE_ID");
// 本地数据库1服务的bean注入
test1Service = (IZhptdbService) sourceMap.get("本地数据库1");
// 判断是否可执行新一批采集,不等于0则可执行
batchId = zhptdbService.determine(String.valueOf(scheduleId));// 这是我自己的方法,可无视
if (batchId != 0) {
// 创建本批次实例,依赖的配置为当前轮询规则的配置
zhptdbService.createBatchKPIInt(batchId,scheduleId);
logger.info("当前轮询规则为:"+scheduleId+" 当前批次为:"+batchId+" 执行健康度采集。");
logger.info("本批次采集完成:" + DateUtil.getDateNow("yyyy-MM-dd HH:mm:ss"));
} else {
logger.info("存在未采集完成的指标:" + DateUtil.getDateNow("yyyy-MM-dd HH:mm:ss"));
}
}
}
以上就是我遇到的两种配置,顺带一提,两个Quartz使用的包版本都为2.2.1
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
至于corn表达式的话可以参考这篇文章:Quartz中时间表达式的设置-----corn表达式 (转)