Spring Task定時(shí)任務(wù)的完整使用教學(xué)
一、Spring Task 概述
1.1 核心優(yōu)勢(shì)
- 輕量級(jí):無(wú)需額外依賴,Spring 核心包自帶
- 簡(jiǎn)單易用:基于注解配置,上手快
- 集成度高:與 Spring 生態(tài)無(wú)縫集成
- 功能完善:支持多種觸發(fā)方式、異步執(zhí)行、異常處理等
1.2 適用場(chǎng)景
- 數(shù)據(jù)定時(shí)備份與清理
- 定時(shí)發(fā)送郵件/短信通知
- 定時(shí)統(tǒng)計(jì)報(bào)表生成
- 系統(tǒng)狀態(tài)定時(shí)監(jiān)控
- 定時(shí)同步第三方數(shù)據(jù)
二、案例:5分鐘實(shí)現(xiàn)第一個(gè)定時(shí)任務(wù)
2.1 環(huán)境準(zhǔn)備
創(chuàng)建一個(gè)標(biāo)準(zhǔn)的 SpringBoot 項(xiàng)目,無(wú)需添加額外依賴(SpringBoot 2.x 及以上版本已默認(rèn)包含 spring-context 依賴)。
2.2 開(kāi)啟定時(shí)任務(wù)支持
在 SpringBoot 啟動(dòng)類(lèi)上添加 @EnableScheduling 注解,開(kāi)啟定時(shí)任務(wù)自動(dòng)配置:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling // 開(kāi)啟定時(shí)任務(wù)支持
public class TaskApplication {
public static void main(String[] args) {
SpringApplication.run(TaskApplication.class, args);
}
}
2.3 創(chuàng)建定時(shí)任務(wù)類(lèi)
創(chuàng)建一個(gè)普通的 Spring Bean,在需要定時(shí)執(zhí)行的方法上添加 @Scheduled 注解:
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class SimpleTask {
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 每隔5秒執(zhí)行一次
@Scheduled(fixedRate = 5000)
public void printCurrentTime() {
System.out.println("當(dāng)前時(shí)間:" + LocalDateTime.now().format(formatter));
}
}
2.4 運(yùn)行測(cè)試
啟動(dòng) SpringBoot 應(yīng)用,控制臺(tái)會(huì)每隔5秒輸出一次當(dāng)前時(shí)間,說(shuō)明定時(shí)任務(wù)已成功運(yùn)行。
三、核心注解詳解
3.1 @EnableScheduling
- 作用:開(kāi)啟 Spring 定時(shí)任務(wù)的自動(dòng)配置
- 位置:通常添加在啟動(dòng)類(lèi)或配置類(lèi)上
- 原理:該注解會(huì)導(dǎo)入
SchedulingConfiguration配置類(lèi),自動(dòng)注冊(cè)ScheduledAnnotationBeanPostProcessor,用于掃描帶有@Scheduled注解的方法并創(chuàng)建定時(shí)任務(wù)
3.2 @Scheduled
@Scheduled 是最核心的注解,用于標(biāo)記一個(gè)方法為定時(shí)任務(wù)方法。它提供了多種屬性來(lái)配置任務(wù)的執(zhí)行規(guī)則:
| 屬性 | 類(lèi)型 | 說(shuō)明 |
|---|---|---|
| cron(重點(diǎn)) | String | 使用 cron 表達(dá)式定義執(zhí)行規(guī)則 |
| fixedRate | long | 從上一次執(zhí)行開(kāi)始時(shí)間算起,間隔指定毫秒數(shù)執(zhí)行 |
| fixedDelay | long | 從上一次執(zhí)行結(jié)束時(shí)間算起,間隔指定毫秒數(shù)執(zhí)行 |
| initialDelay | long | 首次執(zhí)行延遲的毫秒數(shù) |
| zone | String | cron 表達(dá)式使用的時(shí)區(qū),默認(rèn)使用服務(wù)器本地時(shí)區(qū) |
四、定時(shí)任務(wù)觸發(fā)方式詳解
4.1 fixedRate 固定頻率執(zhí)行
特點(diǎn):從上一次任務(wù)開(kāi)始執(zhí)行的時(shí)間點(diǎn)開(kāi)始計(jì)算,間隔指定時(shí)間后執(zhí)行下一次任務(wù)。
// 每隔5秒執(zhí)行一次,無(wú)論上一次任務(wù)執(zhí)行了多久
@Scheduled(fixedRate = 5000)
public void fixedRateTask() {
System.out.println("fixedRate任務(wù)執(zhí)行:" + LocalDateTime.now());
}
注意:如果任務(wù)執(zhí)行時(shí)間超過(guò)了 fixedRate 設(shè)置的間隔時(shí)間,下一次任務(wù)會(huì)立即執(zhí)行,不會(huì)等待。例如:任務(wù)執(zhí)行需要8秒,fixedRate=5秒,那么任務(wù)會(huì)連續(xù)執(zhí)行,沒(méi)有間隔。
4.2 fixedDelay 固定延遲執(zhí)行
特點(diǎn):從上一次任務(wù)執(zhí)行結(jié)束的時(shí)間點(diǎn)開(kāi)始計(jì)算,間隔指定時(shí)間后執(zhí)行下一次任務(wù)。
// 上一次任務(wù)執(zhí)行結(jié)束后,延遲3秒執(zhí)行下一次
@Scheduled(fixedDelay = 3000)
public void fixedDelayTask() {
System.out.println("fixedDelay任務(wù)執(zhí)行:" + LocalDateTime.now());
}
適用場(chǎng)景:任務(wù)執(zhí)行時(shí)間不固定,需要確保兩次任務(wù)之間有固定的間隔時(shí)間。
4.3 initialDelay 首次執(zhí)行延遲
initialDelay 可以與 fixedRate 或 fixedDelay 配合使用,指定應(yīng)用啟動(dòng)后,首次執(zhí)行任務(wù)的延遲時(shí)間。
// 應(yīng)用啟動(dòng)后延遲10秒,然后每隔5秒執(zhí)行一次
@Scheduled(initialDelay = 10000, fixedRate = 5000)
public void initialDelayTask() {
System.out.println("initialDelay任務(wù)執(zhí)行:" + LocalDateTime.now());
}
4.4 cron 表達(dá)式(最靈活)
cron 表達(dá)式是一種強(qiáng)大的時(shí)間表達(dá)式,可以精確到秒,定義復(fù)雜的執(zhí)行規(guī)則。
cron 表達(dá)式結(jié)構(gòu)
cron 表達(dá)式由6或7個(gè)字段組成,空格分隔:
秒 分 時(shí) 日 月 周 [年]
- 年字段是可選的,通常省略
- 每個(gè)字段可以使用特殊字符表示不同的含義
常用特殊字符
*:表示該字段的所有可能值?:表示不指定值,用于日和周字段互斥-:表示范圍,:表示枚舉多個(gè)值/:表示步長(zhǎng)
常用 cron 表達(dá)式示例
// 每天凌晨0點(diǎn)執(zhí)行
@Scheduled(cron = "0 0 0 * * ?")
public void dailyTask() {}
// 每天上午9點(diǎn)到下午6點(diǎn),每隔半小時(shí)執(zhí)行一次
@Scheduled(cron = "0 0/30 9-18 * * ?")
public void workHourTask() {}
// 每周一至周五的上午10點(diǎn)15分執(zhí)行
@Scheduled(cron = "0 15 10 ? * MON-FRI")
public void weekdayTask() {}
// 每月1號(hào)凌晨1點(diǎn)執(zhí)行
@Scheduled(cron = "0 0 1 1 * ?")
public void monthlyTask() {}
// 每10秒執(zhí)行一次
@Scheduled(cron = "*/10 * * * * ?")
public void every10SecondsTask() {}
在線 cron 表達(dá)式生成工具
五、任務(wù)執(zhí)行器(TaskExecutor)配置
5.1 默認(rèn)執(zhí)行器的問(wèn)題
Spring Task 默認(rèn)使用單線程的任務(wù)執(zhí)行器。如果有多個(gè)定時(shí)任務(wù),它們會(huì)排隊(duì)執(zhí)行,一個(gè)任務(wù)阻塞會(huì)導(dǎo)致其他任務(wù)延遲執(zhí)行。
5.2 自定義線程池
創(chuàng)建一個(gè)配置類(lèi),實(shí)現(xiàn) SchedulingConfigurer 接口,自定義任務(wù)執(zhí)行器:
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
// 核心線程數(shù)
scheduler.setPoolSize(10);
// 線程名前綴
scheduler.setThreadNamePrefix("task-scheduler-");
// 等待任務(wù)完成后關(guān)閉
scheduler.setWaitForTasksToCompleteOnShutdown(true);
// 等待時(shí)間
scheduler.setAwaitTerminationSeconds(60);
// 初始化
scheduler.initialize();
taskRegistrar.setTaskScheduler(scheduler);
}
}
5.3 配置參數(shù)說(shuō)明
setPoolSize(int poolSize):設(shè)置線程池核心線程數(shù),建議根據(jù)任務(wù)數(shù)量和執(zhí)行時(shí)間調(diào)整setThreadNamePrefix(String prefix):設(shè)置線程名前綴,方便日志排查setWaitForTasksToCompleteOnShutdown(boolean):設(shè)置是否等待任務(wù)完成后關(guān)閉線程池setAwaitTerminationSeconds(int seconds):設(shè)置等待任務(wù)完成的最長(zhǎng)時(shí)間
六、異步定時(shí)任務(wù)
6.1 需求情況
即使配置了多線程的任務(wù)執(zhí)行器,同一個(gè)任務(wù)的多次執(zhí)行仍然是串行的。如果任務(wù)執(zhí)行時(shí)間較長(zhǎng),會(huì)導(dǎo)致任務(wù)堆積。
使用異步定時(shí)任務(wù)可以讓同一個(gè)任務(wù)的多次執(zhí)行并行處理。
6.2 開(kāi)啟異步支持
在啟動(dòng)類(lèi)或配置類(lèi)上添加 @EnableAsync 注解:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@EnableAsync // 開(kāi)啟異步支持
public class TaskApplication {
public static void main(String[] args) {
SpringApplication.run(TaskApplication.class, args);
}
}
6.3 創(chuàng)建異步定時(shí)任務(wù)
在定時(shí)任務(wù)方法上添加 @Async 注解:
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class AsyncTask {
@Async
@Scheduled(fixedRate = 1000)
public void asyncTask() throws InterruptedException {
System.out.println("異步任務(wù)開(kāi)始執(zhí)行:" + Thread.currentThread().getName());
// 模擬任務(wù)執(zhí)行3秒
Thread.sleep(3000);
System.out.println("異步任務(wù)執(zhí)行結(jié)束:" + Thread.currentThread().getName());
}
}
運(yùn)行后會(huì)發(fā)現(xiàn),即使任務(wù)執(zhí)行需要3秒,仍然會(huì)每隔1秒啟動(dòng)一個(gè)新的任務(wù),每個(gè)任務(wù)在不同的線程中執(zhí)行。
6.4 自定義異步線程池
默認(rèn)的異步線程池可能無(wú)法滿足生產(chǎn)環(huán)境需求,建議自定義異步線程池:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class AsyncConfig {
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心線程數(shù)
executor.setCorePoolSize(10);
// 最大線程數(shù)
executor.setMaxPoolSize(20);
// 隊(duì)列容量
executor.setQueueCapacity(200);
// 線程存活時(shí)間
executor.setKeepAliveSeconds(60);
// 線程名前綴
executor.setThreadNamePrefix("async-task-");
// 拒絕策略:由調(diào)用線程執(zhí)行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
使用時(shí)指定線程池名稱:
@Async("taskExecutor")
@Scheduled(fixedRate = 1000)
public void asyncTask() {}
七、動(dòng)態(tài)定時(shí)任務(wù)
7.1 為什么需要?jiǎng)討B(tài)定時(shí)任務(wù)
使用 @Scheduled 注解配置的定時(shí)任務(wù)是靜態(tài)的,一旦應(yīng)用啟動(dòng),執(zhí)行規(guī)則就無(wú)法修改。
動(dòng)態(tài)定時(shí)任務(wù)允許在應(yīng)用運(yùn)行時(shí)修改任務(wù)的執(zhí)行時(shí)間、暫停、恢復(fù)和刪除任務(wù)。
7.2 實(shí)現(xiàn)方式
通過(guò) ScheduledTaskRegistrar 注冊(cè)動(dòng)態(tài)任務(wù):
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import java.util.concurrent.ScheduledFuture;
@Configuration
public class DynamicTaskConfig implements SchedulingConfigurer {
private ScheduledTaskRegistrar taskRegistrar;
private ScheduledFuture<?> future;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
this.taskRegistrar = taskRegistrar;
}
// 添加任務(wù)
public void addTask(Runnable task, String cron) {
if (future != null) {
future.cancel(true);
}
future = taskRegistrar.getScheduler().schedule(task, new CronTrigger(cron));
}
// 暫停任務(wù)
public void stopTask() {
if (future != null) {
future.cancel(true);
}
}
}
7.3 動(dòng)態(tài)修改任務(wù)執(zhí)行時(shí)間
創(chuàng)建一個(gè)控制器,提供接口來(lái)動(dòng)態(tài)修改任務(wù)執(zhí)行時(shí)間:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
@RestController
public class DynamicTaskController {
@Autowired
private DynamicTaskConfig dynamicTaskConfig;
@GetMapping("/updateTask")
public String updateTask(@RequestParam String cron) {
Runnable task = () -> System.out.println("動(dòng)態(tài)任務(wù)執(zhí)行:" + LocalDateTime.now());
dynamicTaskConfig.addTask(task, cron);
return "任務(wù)已更新,新的cron表達(dá)式:" + cron;
}
@GetMapping("/stopTask")
public String stopTask() {
dynamicTaskConfig.stopTask();
return "任務(wù)已暫停";
}
}
八、任務(wù)異常處理
8.1 默認(rèn)異常處理
默認(rèn)情況下,如果定時(shí)任務(wù)方法拋出異常,該任務(wù)會(huì)終止執(zhí)行,不會(huì)影響其他任務(wù)。
8.2 全局異常處理
實(shí)現(xiàn) ErrorHandler 接口,創(chuàng)建全局異常處理器:
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.util.ErrorHandler;
import java.lang.reflect.Method;
@Configuration
public class TaskExceptionConfig implements SchedulingConfigurer, AsyncConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(10);
scheduler.setThreadNamePrefix("task-scheduler-");
// 設(shè)置異常處理器
scheduler.setErrorHandler(new TaskErrorHandler());
scheduler.initialize();
taskRegistrar.setTaskScheduler(scheduler);
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncTaskErrorHandler();
}
// 同步任務(wù)異常處理器
public static class TaskErrorHandler implements ErrorHandler {
@Override
public void handleError(Throwable t) {
System.err.println("同步定時(shí)任務(wù)執(zhí)行異常:" + t.getMessage());
t.printStackTrace();
}
}
// 異步任務(wù)異常處理器
public static class AsyncTaskErrorHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
System.err.println("異步定時(shí)任務(wù)執(zhí)行異常:" + method.getName());
ex.printStackTrace();
}
}
}
8.3 方法級(jí)異常處理
在定時(shí)任務(wù)方法內(nèi)部使用 try-catch 塊處理異常:
@Scheduled(fixedRate = 5000)
public void taskWithExceptionHandling() {
try {
// 業(yè)務(wù)邏輯
int result = 1 / 0;
} catch (Exception e) {
System.err.println("任務(wù)執(zhí)行異常:" + e.getMessage());
// 記錄日志、發(fā)送告警等
}
}
九、任務(wù)并發(fā)與冪等性
9.1 并發(fā)問(wèn)題
在以下場(chǎng)景中,定時(shí)任務(wù)可能會(huì)出現(xiàn)并發(fā)執(zhí)行的問(wèn)題:
- 使用異步定時(shí)任務(wù)
- 應(yīng)用集群部署
- 任務(wù)執(zhí)行時(shí)間超過(guò)執(zhí)行間隔
9.2 冪等性設(shè)計(jì)
為了避免并發(fā)執(zhí)行導(dǎo)致的數(shù)據(jù)問(wèn)題,定時(shí)任務(wù)必須保證冪等性。常用的實(shí)現(xiàn)方式:
- 數(shù)據(jù)庫(kù)唯一約束:在關(guān)鍵表上添加唯一索引
- 分布式鎖:使用 Redis、Zookeeper 等實(shí)現(xiàn)分布式鎖
- 狀態(tài)機(jī):記錄任務(wù)執(zhí)行狀態(tài),避免重復(fù)執(zhí)行
9.3 Redis 分布式鎖實(shí)現(xiàn)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class IdempotentTask {
@Autowired
private StringRedisTemplate redisTemplate;
private static final String LOCK_KEY = "task:lock:idempotent";
private static final long LOCK_EXPIRE = 30; // 鎖過(guò)期時(shí)間,秒
@Scheduled(fixedRate = 5000)
public void idempotentTask() {
// 嘗試獲取鎖
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(LOCK_KEY, "locked", LOCK_EXPIRE, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
try {
// 執(zhí)行業(yè)務(wù)邏輯
System.out.println("獲取到鎖,執(zhí)行任務(wù)");
} finally {
// 釋放鎖
redisTemplate.delete(LOCK_KEY);
}
} else {
System.out.println("未獲取到鎖,跳過(guò)本次執(zhí)行");
}
}
}
十、集群環(huán)境下的定時(shí)任務(wù)
10.1 集群環(huán)境的問(wèn)題
在集群環(huán)境下,每個(gè)應(yīng)用實(shí)例都會(huì)執(zhí)行定時(shí)任務(wù),導(dǎo)致任務(wù)重復(fù)執(zhí)行。
10.2 解決方案
- 分布式鎖:如上面的 Redis 分布式鎖實(shí)現(xiàn)
- 任務(wù)調(diào)度中心:使用 XXL-Job、Elastic-Job 等專業(yè)的分布式任務(wù)調(diào)度框架
- 單獨(dú)部署:將定時(shí)任務(wù)單獨(dú)部署在一個(gè)實(shí)例上
10.3 推薦方案
對(duì)于簡(jiǎn)單的定時(shí)任務(wù),使用 Redis 分布式鎖即可滿足需求。對(duì)于復(fù)雜的任務(wù)調(diào)度需求,建議使用專業(yè)的分布式任務(wù)調(diào)度框架,如 XXL-Job。
十一、常見(jiàn)問(wèn)題
11.1 定時(shí)任務(wù)不執(zhí)行
可能原因:
- 忘記添加
@EnableScheduling注解 - 定時(shí)任務(wù)類(lèi)沒(méi)有被 Spring 掃描到(沒(méi)有添加
@Component等注解) - 方法不是 public 的
- 方法有參數(shù)
- 方法返回值不是 void
解決方案:檢查以上幾點(diǎn),確保配置正確。
11.2 任務(wù)執(zhí)行時(shí)間不準(zhǔn)確
可能原因:
- 使用了默認(rèn)的單線程執(zhí)行器,任務(wù)被阻塞
- 服務(wù)器時(shí)間不準(zhǔn)確
- cron 表達(dá)式時(shí)區(qū)設(shè)置不正確
解決方案:
- 配置多線程任務(wù)執(zhí)行器
- 校準(zhǔn)服務(wù)器時(shí)間
- 在
@Scheduled注解中指定時(shí)區(qū):@Scheduled(cron = "0 0 0 * * ?", zone = "Asia/Shanghai")
11.3 任務(wù)重復(fù)執(zhí)行
可能原因:
- 應(yīng)用集群部署
- 任務(wù)執(zhí)行時(shí)間超過(guò)執(zhí)行間隔
- 異步任務(wù)沒(méi)有控制并發(fā)
解決方案:
- 使用分布式鎖
- 調(diào)整任務(wù)執(zhí)行間隔
- 控制異步任務(wù)的并發(fā)數(shù)
十二、總結(jié)
- 合理配置線程池:根據(jù)任務(wù)數(shù)量和執(zhí)行時(shí)間調(diào)整線程池大小,避免任務(wù)阻塞
- 使用異步任務(wù):對(duì)于執(zhí)行時(shí)間較長(zhǎng)的任務(wù),使用異步執(zhí)行
- 保證冪等性:所有定時(shí)任務(wù)都應(yīng)該設(shè)計(jì)為冪等的
- 異常處理:添加全局異常處理和方法級(jí)異常處理,避免任務(wù)終止
- 日志記錄:在任務(wù)執(zhí)行前后記錄詳細(xì)日志,方便問(wèn)題排查
- 監(jiān)控告警:對(duì)任務(wù)執(zhí)行情況進(jìn)行監(jiān)控,異常時(shí)及時(shí)告警
- 避免長(zhǎng)任務(wù):盡量將長(zhǎng)任務(wù)拆分為多個(gè)短任務(wù)
- 集群環(huán)境使用分布式鎖:避免任務(wù)重復(fù)執(zhí)行
以上就是Spring Task定時(shí)任務(wù)的完整使用教學(xué)的詳細(xì)內(nèi)容,更多關(guān)于Spring Task定時(shí)任務(wù)使用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot如何使用assembly打包項(xiàng)目和啟動(dòng)腳本
這篇文章主要介紹了springboot如何使用assembly打包項(xiàng)目和啟動(dòng)腳本問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
Java中ResponseBodyEmitter的實(shí)現(xiàn)
這篇文章主要介紹了Java中ResponseBodyEmitter的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Java中HTTP GET方法調(diào)用帶有body的問(wèn)題解決
這篇文章主要為大家詳細(xì)介紹了Java如何解決HTTP GET方法調(diào)用帶有body的問(wèn)題,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2024-02-02
SpringBoot使用Flyway進(jìn)行數(shù)據(jù)庫(kù)管理的操作方法
Flyway是一個(gè)開(kāi)源的數(shù)據(jù)庫(kù)版本管理工具,并且極力主張“約定大于配置”,簡(jiǎn)單、專注、強(qiáng)大。接下來(lái)通過(guò)本文給大家介紹SpringBoot使用Flyway進(jìn)行數(shù)據(jù)庫(kù)管理的方法,感興趣的朋友一起看看吧2021-09-09
springboot+websocket實(shí)現(xiàn)并發(fā)搶紅包功能
本文主要介紹了springboot+websocket實(shí)現(xiàn)并發(fā)搶紅包功能,主要包含了4種步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
實(shí)現(xiàn)java文章點(diǎn)擊量記錄實(shí)例
這篇文章主要為大家介紹了實(shí)現(xiàn)java文章點(diǎn)擊量記錄實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
Elasticsearch查詢之Match Query示例詳解
這篇文章主要為大家介紹了Elasticsearch查詢之Match查詢示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
Java SpringMVC攔截器與異常處理機(jī)制詳解分析
SpringMVC是一種基于Java,實(shí)現(xiàn)了Web MVC設(shè)計(jì)模式,請(qǐng)求驅(qū)動(dòng)類(lèi)型的輕量級(jí)Web框架,即使用了MVC架構(gòu)模式的思想,將Web層進(jìn)行職責(zé)解耦?;谡?qǐng)求驅(qū)動(dòng)指的就是使用請(qǐng)求-響應(yīng)模型,框架的目的就是幫助我們簡(jiǎn)化開(kāi)發(fā),SpringMVC也是要簡(jiǎn)化我們?nèi)粘eb開(kāi)發(fā)2021-10-10

