Spring中使用定时任务Quartz

来源:互联网 发布:大数据 精准医疗 案例 编辑:程序博客网 时间:2024/06/10 21:06

需要加入的jar包:

<dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-context-support</artifactId>      <version>5.0.0.RELEASE</version>    </dependency><dependency>    <groupId>org.quartz-scheduler</groupId>    <artifactId>quartz</artifactId>    <version>2.3.0</version></dependency>

Quartz的相关核心概念:
1、Job:是一个接口,只有一个execute(JobExecutionContext var1)方法,开发者通过实现该接口来定义需要执行的任务。Job运行时的信息保存在JobDataMap实例中。

2、JobDetail:Quartz在每次执行Job时,都重新创建一个Job实例,所以它不是直接接收一个Job实例,而是接收一个Job实现类,以便通过反射机制实例化Job,因此需要一个类来描述Job的实现类及其相关的静态信息(Job名称、描述等)。

3、Trigger:一个类,描述触发Job执行的时间触发规则。主要有SimpleTrigger和CronTrigger这两个子类。当仅需触发一次或以固定间隔周期性执行时,可以使用SimpleTrigger。当需要复杂的调度方案,可以使用CronTrigger。

4、Calendar:org.quartz.Calendar和java.util.Calendar不一样,它是一些日历特定时间点的集合(每周、每年、五一、十一)。java.util.Calendar代表一个日历时间点(20171001)。

5、Scheduler:代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,二者在Scheduler中拥有各自的组和名称。组及名称是Scheduler查找定位容器中某一对象的依据。因此,组及名称必须唯一(但是Trigger和JobDetail的组和名称可以相同,因为它们是不同的类型)。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。

Job有一个StatefulJob子接口,代表有状态的任务。它是一个没有方法的标签接口,目的是让Quartz知道任务的类型,以便执行不同的方案。

无状态任务在执行时拥有自己的JobDataMap复制,对JobDataMap的更改不会影响下次的执行。而有状态任务共享同一个JobDataMap实例,每次执行任务对JobDataMap的更改会保存下来,会对后面的执行产生影响。

因此,无状态的Job可以并发执行,而有状态的StatefulJob不能并发执行。如果前次的StatefulJob还没有执行完毕,则下次的任务将阻塞等待,直到前次任务执行完毕。避免使用有状态的Job。

使用数据库持久化任务调度信息,则无状态的JobDataMap仅在Scheduler注册任务时保存一次,而有状态的任务的JobDataMap在每次执行任务后都会进行保存。

一、Spring中使用Quartz

1.1、JobDetailFactoryBean
使用该Bean声明JobDetail时,Bean的名字即是任务的名字,如果没有指定所属组,就使用默认组。

<bean name="jobdetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">        <!--实现Job接口的任务类-->        <property name="jobClass" value="com.smart.service.SampleJob"/>        <!--设置一个键,将Spring的ApplicationContext的引用保存到JobDataMap中,以便在Job的代码中访问-->        <property name="applicationContextJobDataKey" value="applicationContext"/>        <!--为任务所对应的JobDataMap提供值-->        <property name="jobDataAsMap">            <map>                <entry key="size" value="10"/>            </map>        </property>    </bean>

任务类:

public class SampleJob implements Job {    public void execute(JobExecutionContext jtx) throws JobExecutionException {       Map dataMap=jtx.getJobDetail().getJobDataMap();        //获取保存的值        String size=(String)dataMap.get("size");        //获取Spring的上下文信息,可以访问容器中的其他任何Bean        ApplicationContext ctx=(ApplicationContext)dataMap.get("applicationContext");        //对JobDataMap中保存的值进行修改,要根据任务类型进行区分         //如果实现Job接口,这种更改对于下一次执行是不可见的        //如果实现StatefulJob接口,对于下一次执行是可见的        dataMap.put("size",size+"0");    }}

1.2、MethodInvokingJobDetailFactoryBean
可以将一个Bean的某个方法封装成满足Quartz要求的Job,但是产生的JobDetail不能被序列化,所以不能被持久化到数据库中。

<bean id="sampleDetailJob" class="com.smart.service.SampleDetailJob"/>    <bean id="jobDetail_1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">        <!--引用一个Bean-->        <property name="targetObject" ref="sampleDetailJob"/>       <!--指定目标Bean的方法,可以是static方法和非static方法,但是不能拥有参数-->        <property name="targetMethod" value="execute"/>        <!--指定任务是否有状态  false:不并发,说明有状态 -->        <property name="concurrent" value="false"/>    </bean>

二、创建Trigger
2.1、SimpleTriggerFactoryBean
在默认情况下,通过SimpleTriggerFactoryBean配置的Trigger名称即为Bean的名称,属于默认值。

 <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">        <!--对应的JobDetail-->        <property name="jobDetail" ref="jobdetail"/>        <property name="startDelay" value="1000"/>         <property name="repeatCount" value="100"/>        <property name="repeatInterval" value="2000"/>        <property name="jobDataAsMap">            <map>                <entry key="count" value="10"/>            </map>        </property>    </bean>

在Job中获取Trigger中的dataMap的值:

     Map triggerMap=jtx.getTrigger().getJobDataMap();        String count=(String)triggerMap.get("count");        //对dataMap的更改不会持久化,也不影响下次的执行        triggerMap.put("count","30");

2.2、CronTriggerFactorBean
新增的属性和配置与SimpleTriggerFactoryBean相似,

 <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">        <property name="jobDetail" ref="jobdetail"/>        <property name="cronExpression" value="0 0 5 * * * ?"/>    </bean>

三、创建Scheduler
3.1、SchedulerFactoryBean

 <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">       <!--初始化完成后,延迟10秒启动,默认是0,立即启动,一般情况下,延迟一小段时间启动,以便Spring可以初始化剩余的Bean-->       <property name="startupDelay" value="10"/>        <!--配置多个trigger-->        <property name="triggers">            <list>                <ref bean="cronTrigger"/>                <ref bean="simpleTrigger"/>            </list>        </property>        <property name="schedulerContextAsMap">            <map>                <entry key="timeout" value="30"/>            </map>        </property>        <!--Quartz本身有一个默认的配置文件,也可以自己设置自定义的Quartz的配置文件覆盖默认的-->        <property name="configLocation" value="classpath:quartz.properties"/>        <!--也可以直接通过属性配置,而不是配置文件-->        <property name="quartzProperties">            <props>             <!--数据保存到数据库而不是内存中-->                <prop key="org.quartz.jobStore.class">                    org.quartz.impl.jdbcjobstore.JobStoreTX                </prop>            </props>        </property>    </bean>