@Scheduled注释提供了一种在Spring驱动的应用程序中创建计划任务的简便方法。 我们可以使用它通过定期调度或cron表达式来调度我们的任务。
尽管时段调度也可能有用,但是cron表达式使我们对调度任务的调用有了更多的控制。 这就是为什么它们在现实生活中非常有用的原因。 但是,如果执行不正确,使用cron表达式将有一个主要缺点。 让我们找出那是什么。
创建计划任务
假设我们要创建一个任务,该任务每秒被调用一次,并且仅将一条消息写入日志。 我们可以按照以下步骤创建此任务(由于本文的第二部分对此进行了描述,因此我们将跳过所需的配置):
- 创建一个名为ScheduledJob的类。
- 用@Component注释对类进行注释。
- 创建一个私有的Logger字段并实例化创建的字段。
- 创建一个名为run()的公共方法,并确保其返回类型为void 。
- 使用@Scheduled注释对方法进行注释,并将使用的cron表达式设置为cron属性的值( Spring中的Cron Scheduler提供了有关cron表达式的详尽概述)。
- 通过将单个消息写入日志来实现该方法。
ScheduledJob类的源代码如下所示:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class ScheduledJob {private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledJob.class);@Scheduled(cron = "0-59 * * * * *")public void run() {LOGGER.debug("run()");}
}
我们实现的问题是cron表达式是硬编码的。 这意味着不可能在不同的环境中使用不同的配置。
如果要在不同的环境中使用不同的调度配置,则必须在创建部署的二进制文件之前手动更改配置。
这自然是容易出错的。 由于使用错误的调度配置的后果可能很严重,因此我们必须找到一种方法来将cron表达式从代码移动到项目的配置文件中。
将Cron表达式移动到属性文件
在寻找解决问题的方法时,我遇到了这个问题。 本博客文章中描述的解决方案就是基于该讨论。
我们解决方案的要求如下:
- 生产和开发环境必须具有不同的配置。
- 在开发环境中运行计划任务时,必须每秒调用一次。
- 在生产环境中运行计划任务时,必须每分钟调用一次。
我们可以通过执行以下步骤来满足这些要求:
- 配置Maven。
- 创建属性文件。
- 配置应用程序上下文。
- 修改任务类。
让我们开始吧。
配置Maven
我们可以按照以下步骤配置Maven:
- 为开发和生产环境创建概要文件。
- 配置资源过滤。
让我们继续前进,找出实现方法。
为开发和生产环境创建配置文件
我们记得,我们必须为开发和生产环境创建Maven配置文件。
我们可以按照以下步骤创建在开发环境中使用的配置文件:
- 将新的配置文件添加到POM文件的配置文件部分。
- 将创建的配置文件的ID设置为“ dev”。
- 确保默认情况下开发配置文件处于活动状态。
- 创建一个名为build.profile.id的属性,并将其值设置为'dev'。
我们可以按照以下步骤创建生产资料:
- 将新的配置文件添加到POM文件的配置文件部分。
- 将创建的配置文件的ID设置为“ prod”。
- 创建一个名为build.profile.id的属性,并将其值设置为'prod'。
pom.xml文件的配置文件部分如下所示:
<profiles><profile><id>dev</id><activation><activeByDefault>true</activeByDefault></activation><properties><build.profile.id>dev</build.profile.id></properties></profile><profile><id>prod</id><properties><build.profile.id>prod</build.profile.id></properties></profile>
</profiles>
在配置构建的资源过滤时,将使用build.profile.id属性。 让我们看看这是如何完成的。
配置资源过滤
我们可以按照以下步骤配置资源过滤 :
- 配置包含配置文件特定属性的配置文件的位置( build.profile.id属性的值标识使用的配置文件)。
- 配置资源目录的位置并激活资源过滤。
pom.xml文件的相关部分如下所示:
<filters><filter>profiles/${build.profile.id}/config.properties</filter>
</filters>
<resources><resource><filtering>true</filtering><directory>src/main/resources</directory></resource>
</resources>
创建属性文件
我们可以按照以下步骤创建所需的属性文件:
- 我们必须为开发环境创建一个属性文件。
- 我们必须为生产环境创建一个属性文件。
- 我们必须创建一个属性文件,该文件由我们的应用程序读取。
让我们开始吧。
为开发环境创建属性文件
我们可以按照以下步骤为开发环境创建属性文件:
- 在个人档案/ dev目录中创建一个名为config.properties的文件 。
- 在scheduling.job.cron属性的值设置为'0-59 * * * * *'。 这样可以确保任务每秒被调用一次。
profiles / dev / config.properties文件的内容如下所示:
scheduling.job.cron=0-59 * * * * *
为生产环境创建属性文件
我们可以按照以下步骤为生产环境创建属性文件:
- 在个人档案/ prod目录中创建一个名为config.properties的文件 。
- 在scheduling.job.cron属性的值设置为'0 0-59 * * * *'。 这样可以确保每分钟调用一次任务。
profile / prod / config.properties文件的内容如下所示:
scheduling.job.cron=0 0-59 * * * *
创建我们的应用程序的属性文件
我们可以按照以下步骤创建应用程序的属性文件:
- 在src / main / resources目录中创建一个名为application.properties的文件。
- 将schedule.job.cron属性的值设置为'$ {scheduling.job.cron}'。 这样可以确保将占位符替换为正确的cron表达式。
src / main / resources / application.properties文件的内容如下所示:
scheduling.job.cron=${scheduling.job.cron}
配置应用程序上下文
我们可以使用Java配置类或XML配置文件来配置应用程序的应用程序上下文。
下面介绍了这两个选项。
Java配置
我们可以按照以下步骤创建应用程序上下文配置类:
- 创建一个名为ExampleApplicationContext的类。
- 用@Configuration注释对类进行注释。
- 通过使用@EnableScheduling注释对类进行注释来启用调度。
- 用@ComponentScan注释为类添加注释,并配置扫描的软件包。
- 用@PropertySource注释对类进行注释,并确保从称为class.path的属性文件application.properties中加载属性。
- 创建一个新的PropertySourcesPlaceHolderConfigurer bean。
我们的应用程序上下文配置类的源代码如下所示:
import org.springframework.context.annotation.*;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.EnableScheduling;@Configuration
@EnableScheduling
@ComponentScan(basePackages = {"net.petrikainulainen.spring.trenches.scheduling"
})
@PropertySource("classpath:application.properties")
public class ExampleApplicationContext {@Beanpublic PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer();properties.setLocation(new ClassPathResource( "application.properties" ));properties.setIgnoreResourceNotFound(false);return properties;}
}
XML配置
我们可以按照以下步骤创建应用程序上下文配置文件:
- 使用上下文名称空间的property-placeholder元素从名为class.path的属性文件application.properties中加载属性。
- 使用上下文名称空间的注释配置元素来确保从我们的bean类中检测到“常规”注释。
- 使用上下文名称空间的component-scan元素来配置扫描的软件包。
- 通过使用任务名称空间的注释驱动元素来启用调度。
我们的应用程序上下文配置文件的源代码如下所示:
<?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"xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsdhttp://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd"><context:property-placeholder location="classpath:application.properties" ignore-resource-not-found="false"/><context:annotation-config/><context:component-scan base-package="net.petrikainulainen.spring.trenches.scheduling"/><task:annotation-driven/>
</beans>
修改计划任务
最后一步是修改任务类,并确保从application.properties文件中读取了使用的cron表达式。 我们可以通过将@Scheduled批注的cron属性的值设置为'$ {scheduling.job.cron}'来实现。
ScheduledJob类的源代码如下所示:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class ScheduledJob {private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledJob.class);@Scheduled(cron = "${scheduling.job.cron}")public void run() {LOGGER.debug("run()");}
}
摘要
现在,我们创建了一个计划任务,该任务从属性文件中读取使用的cron表达式。 这篇博客文章教会了我们三件事:
- 我们了解到,对使用的cron表达式进行硬编码会使在不同环境中使用不同配置变得困难。
- 我们了解了如何使用Maven将特定于配置文件的配置属性分离为特定于配置文件的配置文件。
- 我们学习了配置应用程序的应用程序上下文并从属性文件中读取使用的cron表达式。
与往常一样,此博客文章的示例应用程序可在Github上获得 。
翻译自: https://www.javacodegeeks.com/2013/07/spring-from-the-trenches-using-environment-specific-cron-expressions-with-the-scheduled-annotation.html