spring-boot 如何實現單次執行程序
spring-boot 單次執行程序
spring-boot做為spring的集大成框架,大部分時候作為WEB服務被集成使用,但某些情況下,需要手動執行一些邏輯的情況下,單次運行的類似腳本的程序也是很有用的。
本文記錄一下使用spring-boot作為單次可執行程序配置方式。
pom.xml
註意:pom.xml部分隻需引入spring-boot-starter模塊,尤其不要引入web模塊,其他非spring本身模塊可以隨意引入
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <!-- 按工程習慣處理parent部分 --> </parent> <groupId>com.leon</groupId> <artifactId>sprint-boot-task</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.0.4</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
主要代碼結構
Service類
@Service public class StatService { public void doSomething() { System.out.println("===================: this is a test service but nothing"); } }
執行邏輯入口類
@Component public class StatTask { private StatService statService; @Autowired public StatTask(StatService statService) { this.statService = statService; } public void doSomething() { statService.doSomething(); } }
Spring-boot 啟動類
@SpringBootApplication public class TaskApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(TaskApplication.class, args); StatTask statTask = context.getBean(StatTask.class); // 獲取邏輯入口類的實例 statTask.doSomething(); } }
如此這般後,啟動這個springboot工程,執行完啟動類中的調用過程後,程序就會自動退出。
基本上,不配置啟用spring mvc和定時Job,這種配置下的springboot就是一個“腳本”程序。
這裡舉個?,上面的代碼加上兩個註解,就會變成常駐進程程序:
執行邏輯入口類
@Component public class StatTask { private StatService statService; @Autowired public StatTask(StatService statService) { this.statService = statService; } @Scheduled(fixedRate = 5000L) // --------------這裡----------------- public void doSomething() { statService.doSomething(); } }
Spring-boot 啟動類
@SpringBootApplication @EnableScheduling // --------------這裡--------------- public class TaskApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(TaskApplication.class, args); StatTask statTask = context.getBean(StatTask.class); statTask.doSomething(); } }
與最上面區別的是,上面隻執行一次,輸出 “this is a test service but nothing” 就完事瞭,進程自動退出,
加上兩個註解後就會每5秒輸出一次 “this is a test service but nothing”,且進程永駐。
當然這種情況下使用腳本語言如python、nodeJs等可能更好一些,但在其他語言不熟的情況下,使用spring-boot來應急也是極好的。
啟動時執行單次任務
最近做任務遇到一個問題,需要在項目啟動時候執行掃描數據庫表的任務,用於異常恢復容災,一開始想的是可不可以使用定時任務
代碼如下 並且在啟動類加上
@EnableScheduling註解就可以實現定時去執行任務瞭
package com.beihui.service.task; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class XXXTask { private Logger logger = LoggerFactory.getLogger(this.getClass()); @Scheduled(cron = "0 0 0 * * ?") public void bTask() { long startCurrentTime = System.currentTimeMillis(); logger.info("開始執行定時任務:" + startCurrentTime); //業務處理 long endTime = System.currentTimeMillis(); logger.info("定時任務:執行結束,花費時間" + (endTime - startCurrentTime)); } @Scheduled(cron = "0 */1 * * * ?") public void runUpdateDbTask() { long startCurrentTime = System.currentTimeMillis(); logger.info("開始執行更新數據庫剩餘次數定時任務:" + startCurrentTime); //業務處理 long endTime = System.currentTimeMillis(); logger.info("定時任務:執行結束,花費時間" + (endTime - startCurrentTime)); } @Scheduled(fixedDelay = 60 * 1000 * 10) public void cTask() { long startCurrentTime = System.currentTimeMillis(); //業務處理 long endTime = System.currentTimeMillis(); logger.info("定時任務:執行結束,花費時間" + (endTime - startCurrentTime)); } }
但是這個並不能單次執行任務,所以後來 使用listener
代碼如下,並在啟動類加上
@ServletComponentScan註解
package xx.xx.xx; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; @WebListener public class XXXListener implements ServletContextListener { private Logger logger = LoggerFactory.getLogger(this.getClass()); //項目啟動執行 @Override public void contextInitialized(ServletContextEvent servletContextEvent) { long startTime = System.currentTimeMillis(); logger.info("開始執行啟動任務,{}"+startTime); //業務處理 long endTime = System.currentTimeMillis(); logger.info("執行啟動任務結束,共花費時間{}"+(startTime-endTime)); } //項目終止時執行 @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { } }
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- springBoot啟動輸出三行日志控制臺自動停止操作
- Spring使用AspectJ的註解式實現AOP面向切面編程
- spring boot整合log4j2及MQ消費處理系統日志示例
- spring boot項目沒有mainClass如何實現打包運行
- Spring Boot源碼實現StopWatch優雅統計耗時