集成Spring+ quartz 分为四步
第一步 POM.XML 添加spring+quartz依赖
<!-- Spring start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!-- Spring 和 quartz 集成需要的jar 包 spring-context-support spring-tx-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
<!-- Spring stop-->
<!-- quartz 定时任务开始-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
<!-- quartz 定时任务结束-->
第二步 定义Spirng和quartz整合的Job 有两个类型的Job:MethodInvokingJobDetailFactoryBean 和 JobDetailFactoryBean
JobDetailFactoryBean
下面配置一个job,继承QuartzJobBean类,调度时候将回调executeInternal方法。我们的调度逻辑写在这个方法里面。jobDataMap 参数提供向jobBean传递参数的功能。
<!-- 定义作业任务Bean JobDetailFactoryBean 来管理作业任务;
当你需要传递数据给Job 时候使用这个JobBean.-->
<bean id="jobDetailFactoryBeanExample" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!--
参考源码,我们可以看到属性jobClass为Class类型,所以不能使用ref来引用一个bean,否则就会因为不能将bean转换为Class类型而出现异常。
<property name="jobClass" ref="simpleJob"/>
必须使用value对jobClass赋值。
<property name="jobClass" value="common.quartz.spring.task002.SimpleJob"/>
-->
<property name="jobClass" value="common.quartz.spring.task002.SimpleJob"/>
<!-- 这里设置的jobDataAsMap可以传递一些参数给作业任务 -->
<property name="jobDataAsMap">
<map>
<entry key="name" value="vincent"/>
<entry key="copyright" value="PLCC"/>
<entry key="key3" value="987"/>
<entry key="anotherBean" value-ref="anotherBean"/>
</map>
</property>
<property name="durability" value="true"/>
<property name="group" value="jobDetail-jobname-group"/>
<property name="name" value="jobDetail-jobname"/>
</bean>
SimpleJob
package common.quartz.spring.task002;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.scheduling.quartz.QuartzJobBean;
/**
* batch-parent.common.quartz.spring <br/>
* Created by PengRong on 2018/1/12. <br/>
* Spring + Quartz 集成后,使用JobDetailFactoryBean来管理作业任务时,我们的作业任务实现类需要继承QuartzJobBean类,并覆盖其executeInternal方法。
* 这个Quartz 作业Bean 有点不友好
* @author PengRong <br/>
* @Description TODO(${END})
* @ClassName: ${CLASS}
* @since 2018-01-12 16:19 <br/>
*/
//@Component("simpleJob") Quartz 调度任务通过class 反射调用的。
/**
* 如果你需要持久化 JobDataMap里面的数据你就需要PersistJobDataAfterExecution注解Job;
* 如果多个触发器调度Scheduling同一个job,为了避免竞争冲突。使用DisallowConcurrentExecution 注解Job
*/
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class SimpleJob extends QuartzJobBean {
public static final String COUNT = "key3";
private AnotherBean anotherBean;
public void setAnotherBean(AnotherBean anotherBean) {
this.anotherBean = anotherBean;
}
/**
* SimpleJob 任务Job 类
* @param context
* @throws JobExecutionException
*/
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
JobKey key = context.getJobDetail().getKey();
//job 唯一标识符
System.out.println("时间是"+new SimpleDateFormat("yyyy-MM-dd- HH-时-mm-分-ss-秒-").format(new Date())+"key: "+key);
JobDataMap map = context.getJobDetail().getJobDataMap();
String name = map.getString("name");
int count=map.getInt(COUNT);
System.out.print("quartzJob task Spring....." + name+"\tkey: "+key+"\t "+count++);
map.put(COUNT,count);
anotherBean.printAnotherMessage();
}
}
anotherBean
package common.quartz.spring.task002;
import org.springframework.stereotype.Component;
/**
* @Package: common.quartz.spring.task002 <br/>
* @Description: 这个类设置成被SimpleJob 引用从而被调用的Job。 <br/>
* @author: PengRong <br/>
* @Date: Created in 2018/1/14 12:40 <br/>
* @Company: PLCC <br/>
* @Copyright: Copyright (c) 2017 <br/>
* @Version: 1.0 <br/>
* @Modified By: <br/>
* @Created by PengRong on 2018/1/14. <br/>
*/
@Component("anotherBean")
public class AnotherBean {
public void printAnotherMessage(){
System.out.println("I am called by Quartz jobBean using CronTriggerFactoryBean");
}
}
MethodInvokingJobDetailFactoryBean
这个类很简单,调度时候调用exampleJob的execute方法。
<!-- 定义作业任务 Bean MethodInvokingJobDetailFactoryBean -->
<!--
如果两个触发器触发调度同一个作业,那么可能造成资源竞争。
将作业类实现StatefulJob接口就可以避免这种情况。
将concurrent设置为false可以避免并发的发生。
-->
<!-- 使用MethodInvokingJobDetailFactoryBean来创建作业对象
下面这个Job 配置就是调用 ExampleJob 类的execute 方法。ExampleJob 只是一个简单方法。
-->
<bean id="methodInvokingJobDetailFactoryBeanExample" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 目标对象,指的是作业任务的实现类 -->
<property name="targetObject" ref="exampleJob"/>
<!-- 目标方法,指的是指定实现类中的哪个方法作为调度时的执行方法;无参数-->
<property name="targetMethod" value="execute"/>
<!-- 是否并发 -->
<property name="concurrent" value="false"/>
<!-- 设置job 的名字和组名 -->
<property name="name" value="spring-quartz-methodInvoking-method"/>
<property name="group" value="spring-quartz-methodInvoking-method-group"/>
</bean>
exampleJob
package common.quartz.spring.task002;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* batch-parent.common.quartz.spring.task002 <br/>
* Created by PengRong on 2018/1/12. <br/>
* Spring + quartz 集成后 任务作业Bean :MethodInvokingJobDetailFactoryBean 的作业类。不用继承任何类和接口
* @author PengRong <br/>
* @Description TODO(${END})
* @ClassName: ${CLASS}
* @since 2018-01-12 16:36 <br/>
*/
@Component("exampleJob")
public class ExampleJob {
public void execute(){
System.out.println("现在是"+new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒").format(new Date())+"\tI am called by MethodInvokingJobDetailFactoryBean using SimpleTriggerFactoryBean");
}
}
第三步 配置触发器,定义了调度的时间规则
MethodInvokingJobDetailFactoryBean 的触发器
<!-- 触发器 simpleTrigger; 配置了作业信息; 下面配置了一个初始延迟 5秒,然后间隔3秒调度任务。-->
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<!-- 这里的JobDetail指的就是我们配置的作业任务的bean -->
<property name="jobDetail" ref="methodInvokingJobDetailFactoryBeanExample" />
<!-- 启动后延迟5秒开始调度任务 -->
<property name="startDelay" value="5000"></property>
<!-- 每3秒重复一次 -->
<property name="repeatInterval" value="3000"></property>
</bean>
jobDetailFactoryBeanExample的触发器
<!-- 触发器 cronTrigger ;
定义一个在周末每隔5秒调用一次的任务的触发器-->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 这里的JobDetail指的就是我们配置的作业任务的bean -->
<property name="jobDetail" ref="jobDetailFactoryBeanExample"/>
<!--cronExpression,cron表达式-->
<property name="cronExpression" value="0/5 * * ? * SAT-SUN"/>
</bean>
定义调度器
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger"></ref>
<ref bean="cronTrigger"/>
</list>
</property>
<!-- 上面触发器已经关联了 任务Job, 所以这个调度器里面可以不用设置任务Job -->
<!-- <property name="jobDetails">
<list>
<ref bean="jobDetailFactoryBeanExample"/>
<ref bean="methodInvokingJobDetailFactoryBeanExample"/>
</list>
</property>-->
</bean>
最后一步测试:
package common.quartz.spring.task002;
import common.BaseTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* SpringQuartzJob Tester.
*
* @author <PengRong>
* @since
* @version 1.0
*/
public class SpringQuartzJobTest extends BaseTest{
@Before
public void before() throws Exception {
}
@After
public void after() throws Exception {
}
/**
*
* Method: execute()
*
*/
@Test
public void testExecute() throws Exception {
System.out.println("Spring 和 Quartz 框架集成 测试.");
Thread.sleep(1000000);
}
}
配置文件(src/main/resources/spring/quartz/spring-quartz.xml
)
<?xml version="1.0" encoding="UTF-8"?>
<beans 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 集成Spring 配置-->
<!-- 第一步:配置Quartz 和Spring 集成后的 作业任务配置 -->
<!-- 定义作业任务Bean JobDetailFactoryBean 来管理作业任务;
当你需要传递数据给Job 时候使用这个JobBean.-->
<bean id="jobDetailFactoryBeanExample" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!--
参考源码,我们可以看到属性jobClass为Class类型,所以不能使用ref来引用一个bean,否则就会因为不能将bean转换为Class类型而出现异常。
<property name="jobClass" ref="simpleJob"/>
必须使用value对jobClass赋值。
<property name="jobClass" value="common.quartz.spring.task002.SimpleJob"/>
-->
<property name="jobClass" value="common.quartz.spring.task002.SimpleJob"/>
<!-- 这里设置的jobDataAsMap可以传递一些参数给作业任务 -->
<property name="jobDataAsMap">
<map>
<entry key="name" value="vincent"/>
<entry key="copyright" value="PLCC"/>
<entry key="key3" value="987"/>
<entry key="anotherBean" value-ref="anotherBean"/>
</map>
</property>
<property name="durability" value="true"/>
<property name="group" value="jobDetail-jobname-group"/>
<property name="name" value="jobDetail-jobname"/>
</bean>
<!-- 定义作业任务 Bean MethodInvokingJobDetailFactoryBean -->
<!--
如果两个触发器触发调度同一个作业,那么可能造成资源竞争。
将作业类实现StatefulJob接口就可以避免这种情况。
将concurrent设置为false可以避免并发的发生。
-->
<!-- 使用MethodInvokingJobDetailFactoryBean来创建作业对象
下面这个Job 配置就是调用 ExampleJob 类的execute 方法。ExampleJob 只是一个简单方法。
-->
<bean id="methodInvokingJobDetailFactoryBeanExample" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!-- 目标对象,指的是作业任务的实现类 -->
<property name="targetObject" ref="exampleJob"/>
<!-- 目标方法,指的是指定实现类中的哪个方法作为调度时的执行方法;无参数-->
<property name="targetMethod" value="execute"/>
<!-- 是否并发 -->
<property name="concurrent" value="false"/>
<!-- 设置job 的名字和组名 -->
<property name="name" value="spring-quartz-methodInvoking-method"/>
<property name="group" value="spring-quartz-methodInvoking-method-group"/>
</bean>
<!-- 第二步:配置Quartz 和Spring 集成后的 触发器配置;触发器定义了调度器调度你的Job 的时间, -->
<!-- 触发器 simpleTrigger; 配置了作业信息; 下面配置了一个初始延迟 5秒,然后间隔3秒调度任务。-->
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<!-- 这里的JobDetail指的就是我们配置的作业任务的bean -->
<property name="jobDetail" ref="methodInvokingJobDetailFactoryBeanExample" />
<!-- 启动后延迟5秒开始调度任务 -->
<property name="startDelay" value="5000"></property>
<!-- 每3秒重复一次 -->
<property name="repeatInterval" value="3000"></property>
</bean>
<!-- 触发器 cronTrigger ;
定义一个在周末每隔5秒调用一次的任务的触发器-->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!-- 这里的JobDetail指的就是我们配置的作业任务的bean -->
<property name="jobDetail" ref="jobDetailFactoryBeanExample"/>
<!--cronExpression,cron表达式-->
<property name="cronExpression" value="0/5 * * ? * SAT-SUN"/>
</bean>
<!-- 第三步:配置Quartz 和Spring 集成后的 调度工厂配置; 组合JobDetails and triggers -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger"></ref>
<ref bean="cronTrigger"/>
</list>
</property>
<!-- 上面触发器已经关联了 任务Job, 所以这个调度器里面可以不用设置任务Job -->
<!-- <property name="jobDetails">
<list>
<ref bean="jobDetailFactoryBeanExample"/>
<ref bean="methodInvokingJobDetailFactoryBeanExample"/>
</list>
</property>-->
</bean>
</beans>
Spring 容器文件 Application.xml
(src/main/resources/spring/Application.xml
)
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"
default-autowire="byName" default-lazy-init="false">
<!-- 采用注解的方式配置bean -->
<context:annotation-config />
<!-- 配置要扫描的包 -->
<context:component-scan base-package="common"/>
<!-- 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 -->
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<!--
<context:component-scan base-package="com.imodule" /> -->
<!--<context:component-scan base-package="com.generated.lifepro" />-->
<!-- 引入资源 -->
<!--<import resource="spring-mybatis.xml" />-->
<!-- <import resource="hydra-config.xml"/> -->
<!-- 配置spring-batch
<import resource="spring-batch.xml"/>
<import resource="dubbo-consumer.xml"/> -->
<!-- 配置Spring-quartz.xml 定时调度器 -->
<import resource="quartz/spring-quartz.xml"/>
<!-- 获取数据库配置属性, 这种方式配置的属性 不能再代码中获取。-->
<!-- <context:property-placeholder location="mysql/mysql-db.properties"/>-->
</beans>
参考:
Spring 4 + Quartz Scheduler Integration Example,这个很好
Spring 4 + Quartz 2 Scheduler Integration Annotation Example using JavaConfig