在Spring中使用Quartz执行定时任务、防止任务并行、在任务中获取Spring管理Bean教程

本教程的重点是防止Quartz任务并行和在任务中获取Spring中Bean的方法,对应教程第三和第四部分。


一、Spring和Quartz相关官方文档地址

Spring:
https://docs.spring.io/spring/docs/current/spring-framework-reference/integration.html#scheduling-quartz
Quartz:
http://www.quartz-scheduler.org/documentation/quartz-2.2.x/tutorials/


二、Spring中使用Quartz

Quartz的文档看前几章,知道Job,JobDetail,Trigger和Scheduler分别是做什么用的即可。Spring中关于Quartz的相关文档需要仔细阅读,其中的相关配置看懂后直接粘贴复制到项目配置文件中,更改为自己需要的配置即可。

  1. 配置JobDetail
    Spring提供了两种配置JobDetail的配置,官方示例如下:

<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="example.ExampleJob"/>
    <property name="jobDataAsMap">
        <map>
            <entry key="timeout" value="5"/>
        map>
    property>
bean>

<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="exampleBusinessObject"/>
    <property name="targetMethod" value="doIt"/>
    <property name="concurrent" value="false"/>
bean>

首先说"JobDetail配置 2",官方介绍如下:Often you just need to invoke a method on a specific object. Using the MethodInvokingJobDetailFactoryBean you can do exactly this。按照官方的意思,就是说简单情况下,如果你的定时任务只是需要调用某个Spring对象的某个方法,可以用这个配置来简单配置下,concurrent设置为false可以防止任务并发执行。这种配置在简单的情况下可用,但是功能不强,用处不大。
重点介绍"JobDetail配置 1":

  • 首先需要配置 jobClass属性,jobClass需要传入一个Job实现类。Spring推荐直接继承QuartzJobBean类,官方示例如下:
package example;

public class ExampleJob extends QuartzJobBean {

    private int timeout;

    /**
     * Setter called after the ExampleJob is instantiated
     * with the value from the JobDetailFactoryBean (5)
     */
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
        // do the actual work
    }

}

executeInternal中进行实际业务逻辑。

  • 其次需要配置jobDataAsMap属性,如上例中,jobDataAsMap配置了一个map,有一个
<entry key="timeout" value="5"/>

只要是继承的QuartzJobBean,就可以通过这种方式直接向Job的属性中传递值,如上例中的

    private int timeout;

    /**
     * Setter called after the ExampleJob is instantiated
     * with the value from the JobDetailFactoryBean (5)
     */
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

然后在executeInternal方法中就可以直接使用timeout的值了,如下:

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println(timeout);
    }
  1. 配置Trigger和Scheduler
    Quartz中常用的Trigger只有两种,官方示例如下:

<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
    
    <property name="jobDetail" ref="jobDetail"/>
    
    <property name="startDelay" value="10000"/>
    
    <property name="repeatInterval" value="50000"/>
bean>


<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="exampleJob"/>
    
    <property name="cronExpression" value="0 0 6 * * ?"/>
bean>
  • simpleTrigger每个一段时间执行一次的计划任务。jobDetail就是前面介绍的JobDetail,startDelay表示系统启动起来后过(延后)多长时间开始执行任务,单位:毫秒。repeatInterval表示任务执行时间间隔,单位:毫秒。
  • cronTrigger是用cron表达式来执行定时任务。关于cron表达式可参考https://blog.csdn.net/lianjunzongsiling/article/details/82228655。jobDetail就是前面介绍的JobDetail。
  1. 配置scheduler
    Quartz中自带的scheduler有两种,其中一种是做测试用的,也就是说只有一个是实际开发用的,所以Spring相应的只推荐一种配置,示例如下:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger"/>
            <ref bean="simpleTrigger"/>
        list>
    property>
bean>

上面配置可直接粘贴复制拿来用,list里配置所有需要使用的trigger。


三、防止Quartz任务并行(干货一)

按照Spring的官方文档,只介绍说MethodInvokingJobDetailFactoryBean(请参看教程前面相关部分)有一个concurrent属性可以用来控制任务是否可以并行。请注意,这个"concurrent"属性是MethodInvokingJobDetailFactoryBean独有的,JobDetailFactoryBean是没有这个属性的,所以是无法JobDetailFactoryBean配置concurrent属性的。网上很多教程说给"JobDetailFactoryBean"配置"concurrent"来防止Quartz任务并行是错误的。由于MethodInvokingJobDetailFactoryBean功能太弱,实际开发中用不多,所以防止JobDetailFactoryBean任务并行是最重要,配置很简单,如下:

package example;

//只需要在Job类上加上这个注解即可
@DisallowConcurrentExecution
public class ExampleJob extends QuartzJobBean {

    private int timeout;

    /**
     * Setter called after the ExampleJob is instantiated
     * with the value from the JobDetailFactoryBean (5)
     */
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
        // do the actual work
    }

}

如上示例,只需要在Job类上加上@DisallowConcurrentExecution注解即可。这才是正确的方法。


四、在任务中获取Spring管理Bean(干货二)

详情请见:https://blog.csdn.net/lianjunzongsiling/article/details/53690956
原理很简单,通过ContextLoader工具的getCurrentWebApplicationContext()方法获取WebApplicationContext,然后通过WebApplicationContext的相关方法获取Bean(通常我们需要获取的类也就是各种Service了,这种情况下用这种办法是最简单的)。


原创不易,转帖请注明出处 — ShiZhongqi

你可能感兴趣的:(在Spring中使用Quartz执行定时任务、防止任务并行、在任务中获取Spring管理Bean教程)