56

如何为基于 Spring 的@Scheduled cron 作业配置时区?

背景:

我有一份工作每天执行一次,比如下午 2 点,使用 Spring 的@Scheduled注释:

@Scheduled(cron = "0 0 14 * * *")
public void execute() {
    // do scheduled job
}

问题是不同服务器之间的 2 PM 不同,因为 Spring 在TimeZone.getDefault() 内部使用 on 。此外,JavaDoc ofTimeZone.getDefault() 声明:

获取此主机的默认时区。默认时区的来源可能因实现而异。

换言之,时区未确定。它可能取决于 JVM 实现、服务器时区配置、服务器位置和/或其他未知因素。因此,cron 作业在不同服务器上的不同时间触发,除非有办法明确设置应该使用哪个时区?

我正在使用 Spring 3.2.2。


更新

从 Spring 4 开始,Spring Jira 问题SPR-10456已得到解决。因此,@Scheduled注释具有正是用于此目的的新区域属性。

4

5 回答 5

43

事实证明我无法使用@Scheduled注释,但我实施了一种解决方法。在SchedulingConfigurer的 JavaDoc 中指出:

[SchedulingConfigurer is] 通常用于设置在执行计划任务时使用的特定 TaskScheduler bean,或以编程方式注册计划任务,而不是使用 @Scheduled 注释的声明性方法。

接下来,我更改了 cron 作业以实现Runnable接口,然后更新了我的配置文件以实现SchedulingConfigurer,见下文:

@Configuration
@EnableScheduling
@ComponentScan("package.that.contains.the.runnable.job.bean")
public class JobConfiguration implements SchedulingConfigurer {

    private static final String cronExpression = "0 0 14 * * *";
    private static final String timeZone = "CET";

    @Autowired
    private Runnable cronJob;

    @Bean
    CronTrigger cronTrigger() {
        return new CronTrigger(cronExpression, TimeZone.getTimeZone(timeZone));
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addCronTask(new CronTask(job, cronTrigger()));
    }
}

请阅读@EnableScheduling的JavaDoc了解更多信息。


更新

从 Spring 4 开始,Spring Jira 问题SPR-10456已得到解决。因此,@Scheduled注释有一个新的区域属性正是为了这个目的,例如

@Scheduled(cron = "0 0 14 * * *", zone = "CET")
public void execute() {
    // do scheduled job
}
于 2013-04-13T15:04:21.263 回答
22

zoneannotation 中有元素@Scheduled,从 4.0 版本开始。

您可以将时区插入为可以被java.util.TimeZone.

于 2015-12-10T09:24:09.303 回答
8

你的代码应该是这样的:

@Scheduled(cron = "0 0 14 * * *", zone = "GMT-5")
    public void execute() {
     // do scheduled job
}

“Zone”将是所需国家/地区的时区。

这是一个关于 Spring 计划任务的不错的教程:

https://www.baeldung.com/cron-expressions

于 2019-07-25T05:26:22.460 回答
2

您还可以@Scheduled在 spring-boot 中使用带有标签的时区,如下所示:

@Scheduled(cron = "0 0 14 * * *" , zone = "GMT+5:00")
public void execute() {
    // do the scheduled job
}
于 2019-03-13T06:31:09.720 回答
0

我怀疑您是否希望不同的工作或应用程序的一部分使用不同的时区。假设您希望它保持一致和干燥,或者将所有服务器上的操作系统配置为具有一致的时区,或者为所有应用程序服务器设置 user.timezone Java 系统属性。集中管理配置(操作系统、应用程序服务器),对于那个 puppet 和 chef 来说非常有用。

于 2013-04-14T09:48:20.377 回答