javascript
与Spring的计划任务一起按时运行
您是否需要每天像鬧鐘一樣在同一時間運行某個流程? 然后,Spring的預定任務適合您。 允許您使用@Scheduled注釋方法,以使其在指定的時間或內部間隔運行。 在本文中,我們將研究如何設置一個可以使用計劃任務的項目,以及如何使用不同的方法來定義它們的執行時間。
我將在本文中使用Spring Boot,以使依賴關系變得簡潔而又簡單,這是因為可以對spring-boot-starter依賴項進行調度,該依賴項將以某種方式包含在幾乎每個Spring Boot項目中。 這使您可以使用任何其他啟動程序依賴項,因為它們會引入spring-boot-starter及其所有關系。 如果要包括確切的依賴項本身,請使用spring-context 。
您可以使用spring-boot-starter 。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><version>2.0.0.RC1</version> </dependency>或直接使用spring-context 。
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.3.RELEASE</version> </dependency>創建計劃任務非常簡單。 將@Scheduled批注添加到希望自動運行的任何方法中,并將@EnableScheduling包含在配置文件中。
因此,例如,您可能會遇到類似以下的內容。
@Component public class EventCreator {private static final Logger LOG = LoggerFactory.getLogger(EventCreator.class);private final EventRepository eventRepository;public EventCreator(final EventRepository eventRepository) {this.eventRepository = eventRepository;}@Scheduled(fixedRate = 1000)public void create() {final LocalDateTime start = LocalDateTime.now();eventRepository.save(new Event(new EventKey("An event type", start, UUID.randomUUID()), Math.random() * 1000));LOG.debug("Event created!");} }這里有很多代碼對于運行計劃任務并不重要。 正如我在一分鐘前說過的,我們需要在方法上使用@Scheduled ,它將自動開始運行。 因此,在上面的示例中, create方法將每隔1000毫秒(1秒)開始運行,如注釋的fixedRate屬性所示。 如果我們想更改其運行頻率,則可以增加或減少fixedRate時間,或者可以考慮使用可用的不同調度方法。
因此,您可能想知道這些其他方法是正確的嗎? 好了,它們就在這里(我還將在此處包括fixedRate )。
- fixedRate在fixedRate調用之間以固定的毫秒周期執行該方法。
- fixedRateString一樣的fixedRate ,但有一個字符串值來代替。
- fixedDelay在一次調用結束與下一次調用之間以固定的毫秒周期執行該方法。
- fixedDelayString一樣fixedDelay但一個字符串值來代替。
- cron使用類似cron的表達式來確定何時執行該方法(我們將在以后更深入地介紹此方法)。
@Scheduled批注還有一些其他實用程序屬性。
- zone指示將解析cron表達式的時區,如果不包括時區,它將使用服務器的默認時區。 因此,如果您需要它在特定時區運行,例如香港,則可以使用zone = "GMT+8:00" 。
- initialDelay延遲第一次執行計劃任務的毫秒數,需要使用固定速率或固定延遲屬性之一。
- initialDelayString同為initialDelay但一個字符串值來代替。
以下是一些使用固定速率和延遲的示例。
@Scheduled(fixedRate = 1000)與之前相同,每1秒運行一次。
@Scheduled(fixedRateString = "1000")同上。
@Scheduled(fixedDelay = 1000)在上一次調用完成后運行1秒。
@Scheduled(fixedRate = 1000, initialDelay = 5000)每秒運行一次,但要等待5秒鐘才能首次執行。
現在來看一下cron屬性,它可以對任務的計劃進行更多控制,讓我們定義任務運行的秒數,分鐘數和小時數,甚至可以進一步指定任務的運行年限。
以下是構建cron表達式的組件的細分。
- Seconds值可以為0-59或特殊字符, - * / 。
- Minutes值可以為0-59或特殊字符, - * / 。
- Hours值可以為0-59或特殊字符, - * / 。
- Day of month可以具有值1-31或特殊字符, - * ? / LWC , - * ? / LWC 。
- Month值可以為1-12 , JAN-DEC或特殊字符, - * / 。
- Day of week可以具有值1-7 , SUN-SAT或特殊字符, - * ? / LC # , - * ? / LC # 。
- Year可以為空,值為1970-2099或特殊字符, - * / 。
為了更加清楚起見,我將細目分類組合成一個由字段標簽組成的表達式。
@Scheduled(cron = "[Seconds] [Minutes] [Hours] [Day of month] [Month] [Day of week] [Year]")請不要在表達式中包括花括號(我使用它們使表達式更清晰)。
在繼續之前,我們需要了解特殊字符的含義。
- *表示所有值,因此,如果在第二個字段中使用,則表示每秒或在天字段中使用,表示每天運行。
- ? 表示沒有特定的值,并且可以在“月的天”或“星期幾”字段中使用,其中使用一個會使另一個無效。 如果我們指定在一個月的15日觸發,則一個? 將在“ Day of week字段中使用。
- -表示值的范圍(例如,小時數字段中的1-3表示小時數1、2和3)。
- ,代表附加價值,例如周一,周三,SUN在本周,說明此一天,在周一,周三和周日。
- /代表增量,例如,秒字段中的0/15從0(0、15、30和45)開始每15秒觸發一次。
- L代表一周或一個月的最后一天。 請記住,在這種情況下,星期六是一周的結束,因此在“星期幾”字段中使用L將在星期六觸發。 可以將其與月日字段中的數字結合使用,例如6L代表月的最后一個星期五,或者L-3這樣的表達式表示月的最后一天。 如果我們在星期幾字段中指定一個值,則必須使用? 在“月”字段中,反之亦然。
- W表示每月的最接近的工作日。 例如,如果15W是工作日,則在每月的第15天觸發,否則它將在最近的工作日運行。 該值不能在日期值列表中使用。
- #指定任務應該在星期幾和星期幾觸發。 例如, 5#2表示該月的第二個星期四。 如果您指定的日期和星期溢出到下個月,則不會觸發。
在這里可以找到有用的資源,其中的解釋稍長一些,這有助于我撰寫本文。
讓我們來看幾個例子。
@Scheduled(cron = "0 0 12 * * ?")每天晚上12點開火。
@Scheduled(cron = "0 15 10 * * ? 2005")2005年每天早上10:15觸發。
@Scheduled(cron = "0/20 * * * * ?")每20秒觸發一次。
有關更多示例,請參閱我前面提到的鏈接, 此處再次顯示。 幸運的是,如果您在編寫一個簡單的cron表達式時遇到麻煩,那么您應該可以在Google中找到所需的方案,因為有人可能已經在Stack Overflow上問了同樣的問題。
要將上述內容與一個小的代碼示例綁定在一起,請參見下面的代碼。
@Component public class AverageMonitor {private static final Logger LOG = LoggerFactory.getLogger(AverageMonitor.class);private final EventRepository eventRepository;private final AverageRepository averageRepository;public AverageMonitor(final EventRepository eventRepository, final AverageRepository averageRepository) {this.eventRepository = eventRepository;this.averageRepository = averageRepository;}@Scheduled(cron = "0/20 * * * * ?")public void publish() {final double average =eventRepository.getAverageValueGreaterThanStartTime("An event type", LocalDateTime.now().minusSeconds(20));averageRepository.save(new Average(new AverageKey("An event type", LocalDateTime.now()), average));LOG.info("Average value is {}", average);} }在這里,我們有一個類,每20秒向Cassandra查詢一次同一時間段內事件的平均值。 同樣,這里的大多數代碼都是@Scheduled批注中的噪音,但在野外看到它可能會有所幫助。 此外,如果您觀察到這一情況,則對于每20秒運行一次的用例,在此處使用頻繁運行任務的情況下,使用fixedRate以及可能使用fixedDelay屬性而不是cron更為合適。
@Scheduled(fixedRate = 20000)是上面使用的cron表達式的fixedRate等效項。
我前面提到的最終要求是將@EnableScheduling批注添加到配置類。
@SpringBootApplication @EnableScheduling public class Application {public static void main(final String args[]) {SpringApplication.run(Application.class);} }作為一個很小的Spring Boot應用程序,我已將@EnableScheduling批注附加到主@SpringBootApplication類。
總而言之,我們可以安排任務使用@Scheduled注釋以及執行之間的毫秒級速率或cron表達式來觸發,以實現無法用前者表達的更佳時序。 對于需要非常頻繁運行的任務,使用fixedRate或fixedDelay屬性就足夠了,但是一旦執行之間的時間變大,則很難快速確定所定義的時間。 發生這種情況時,應使用cron屬性以更好地了解計劃的時間。
這篇文章中使用的少量代碼可以在我的GitHub上找到 。
如果您發現這篇文章很有幫助,并希望在我撰寫新教程時保持最新,請在Twitter上@LankyDanDev關注我。
翻譯自: https://www.javacodegeeks.com/2018/02/running-time-springs-scheduled-tasks.html
總結
以上是生活随笔為你收集整理的与Spring的计划任务一起按时运行的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 三星bada系统手机(三星bada系统手
- 下一篇: @async方法不调用了_在Spring