Spring使用@Scheduled进行定时任务,定的时间可否变

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring使用@Scheduled进行定时任务,定的时间可否变相关的知识,希望对你有一定的参考价值。

参考技术A 定时任务的实现方式有多种,例如JDK自带的Timer+TimerTask方式,Spring 3.0以后的调度任务(Scheduled Task),Quartz等。

Timer+TimerTask是最基本的解决方案,但是比较远古了,这里不再讨论。Spring自带的Scheduled

Task是一个轻量级的定时任务调度器,支持固定时间(支持cron表达式)和固定时间间隔调度任务,支持线程池管理。以上两种方式有一个共同的缺点,那就是应用服务器集群下会出现任务多次被调度执行的情况,因为集群的节点之间是不会共享任务信息的,每个节点上的任务都会按时执行。Quartz是一个功能完善的任务调度框架,特别牛叉的是它支持集群环境下的任务调度,当然代价也很大,需要将任务调度状态序列化到数据库。Quartz框架需要10多张表协同,配置繁多,令人望而却步...

经过折中考虑,还是选择了Spring的Scheduled Task来实现定时任务。如下:

1. Spring配置文件application-context.xml中添加task命名空间和描述。

[html] view plain copy
<beans xmlns=""
xmlns:task=""
xsi:schemaLocation="
/spring-beans.xsd

/spring-task.xsd">
2. 添加调度器和线程池声明。

[html] view plain copy
<task:executor id="taskExecutor" pool-size="10" />
<task:annotation-driven executor="taskExecutor" />
3. 实现调度方法。基本结构如下:

[html] view plain copy
package com.netease.yx.service;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
public class ScheduledService
@Scheduled(cron = "0 0 5 * * *")
public void build()
System.out.println("Scheduled Task");



@Scheduled注解支持秒级的cron表达式,上述声明表示每天5点执行build任务。

前文已经提过,这种方式在单台应用服务器上运行没有问题,但是在集群环境下,会造成build任务在5点的时候运行多次,遗憾的是,Scheduled Task在框架层面没有相应的解决方案,只能靠程序员在应用级别进行控制。

如何控制看

1. 无非是一个任务互斥访问的问题,声明一把全局的逗锁地作为互斥量,哪个应用服务器拿到这把逗锁地,就有执行任务的权利,未拿到逗锁地的应用服务器不进行任何任务相关的操作。
2.这把逗锁地最好还能在下次任务执行时间点前失效。

在项目中我将这个互斥量放在了redis缓存里,1小时过期,这个过期时间是由任务调度的间隔时间决定的,只要小于两次任务执行时间差,大于集群间应用服务器的时间差即可。

完整定时任务类如下:

[html] view plain copy
package com.netease.yx.service;

import javax.annotation.Resource;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import com.netease.yx.service.ICacheService;

@Service
public class ScheduledService
@Resource
private ICacheService cache = null;

private static String CACHE_LOCK = "cache_lock";

private static int EXPIRE_PERIOD = (int)DateUtils.MILLIS_PER_HOUR / 1000;

@Scheduled(cron = "0 0 5 * * *")
public void build()
if (cache.get(CACHE_LOCK) == null)
cache.set(CACHE_LOCK, true, EXPIRE_PERIOD);
doJob();


本回答被提问者采纳

使用spring提供的@Scheduled注解创建定时任务

使用方法

操作非常简单,只要按如下几个步骤配置即可

1. 导入jar包或添加依赖,其实定时任务只需要spring-context即可,当然起服务还需要spring-web;

2. 编写定时任务类和方法,在方法上加@Scheduled注解,注意定时方法不能有返回值,如果采用包扫描方式注册bean,还需要在类上加组件注解;

3. 在spring容器中注册定时任务类;

4. 在spring配置文件中开启定时功能。

 

示例Demo

maven依赖

<dependency>
  <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.1.6.RELEASE</version>
</dependency>

 

定时任务类

@Component(value = "scheduleJob")
public class ScheduleJob {

    /**
     * 固定间隔时间执行任务,单位为微秒
     */
    @Scheduled(fixedDelay = 2000)
    public void timeJob() {
        System.out.println("2s过去了......");
    }

    /**
     * 使用cron表达式设置执行时间
     */
    @Scheduled(cron = "*/5 * * * * ?")
    public void cronJob() {
        System.out.println("cron表达式设置执行时间");
    }
}

 

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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!--扫描指定包下加了组件注解的bean-->
    <context:component-scan base-package="cn.monolog.diana.schedule" />

</beans>

 

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:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/task
       http://www.springframework.org/schema/task/spring-task.xsd">

    <!--开启定时功能-->
    <task:executor id="executor" pool-size="10" queue-capacity="128" />
    <task:scheduler id="scheduler" pool-size="10" />
    <task:annotation-driven executor="executor" scheduler="scheduler" />

</beans>

 

启动服务后,控制台会输出如下语句

2s过去了......
2s过去了......
cron表达式设置执行时间
2s过去了......
2s过去了......
2s过去了......
cron表达式设置执行时间
2s过去了......
2s过去了......

 

指定定时任务执行时间的方式

从上面的demo可以看出,定时任务的执行时间主要有两种设置方式:

1. 使用@Scheduled注解的fixedDelay属性,只能指定固定间隔时长;

2. 使用@Scheduled注解的cron属性,可以指定更丰富的定时方式。

 

那么问题来了,这个cron表达式该怎么写?

以上是关于Spring使用@Scheduled进行定时任务,定的时间可否变的主要内容,如果未能解决你的问题,请参考以下文章

spring @Scheduled注解执行定时任务

Spring使用@Scheduled注解配置定时任务

sae中使用 spring Scheduled 定时任务 怎么弄

使用spring提供的@Scheduled注解创建定时任务

使用轻量级Spring @Scheduled注解执行定时任务

在Spring项目中使用@Scheduled注解定义简单定时任务