SpringBoot?整合?Quartz?定時(shí)任務(wù)框架詳解
前言
在選擇技術(shù)棧之前,一定要先明確一件事情,你真的需要用它嗎?還有其他方式可以使用嗎?
相比其他技術(shù)技術(shù),優(yōu)點(diǎn)在哪里呢?使用了之后的利與弊等等。
寫(xiě)這個(gè)主要是因?yàn)橐恢毕雽?xiě)一下定時(shí)任務(wù)這個(gè)主題,這個(gè)算是寫(xiě)那篇文前期的鋪墊和基礎(chǔ)吧~
本文沒(méi)有聊到 Java
其他的實(shí)現(xiàn)定時(shí)任務(wù)的方法啥的~,只是對(duì)使用 Quartz 做了一個(gè)小實(shí)踐
一、簡(jiǎn)單聊一聊 Quartz
Quartz 是一個(gè)完全由 Java 編寫(xiě)的開(kāi)源作業(yè)調(diào)度框架,為在 Java 應(yīng)用程序中進(jìn)行作業(yè)調(diào)度提供了簡(jiǎn)單卻強(qiáng)大的機(jī)制。
Quartz 其實(shí)就是通過(guò)一個(gè)調(diào)度線程不斷的掃描數(shù)據(jù)庫(kù)中的數(shù)據(jù)來(lái)獲取到那些已經(jīng)到點(diǎn)要觸發(fā)的任務(wù),然后調(diào)度執(zhí)行它的。這個(gè)線程就是 QuartzSchedulerThread類。其run方法中就是quartz的調(diào)度邏輯。
另外,這是一個(gè)Demo,木有考慮并發(fā)、多任務(wù)執(zhí)行等等狀態(tài)的發(fā)生及處理情況,見(jiàn)諒。
1.1、Quartz 概念
Quartz 的幾個(gè)核心概念:
- Job
表示一個(gè)工作,要執(zhí)行的具體內(nèi)容。此接口中只有一個(gè)方法
?void execute(JobExecutionContext context)
JobDetail 表示一個(gè)具體的可執(zhí)行的調(diào)度程序,Job 是這個(gè)可執(zhí)行程調(diào)度程序所要執(zhí)行的內(nèi)容,另外 JobDetail 還包含了這個(gè)任務(wù)調(diào)度的方案和策略。
Trigger 代表一個(gè)調(diào)度參數(shù)的配置,什么時(shí)候去調(diào)。
Scheduler 代表一個(gè)調(diào)度容器,一個(gè)調(diào)度容器中可以注冊(cè)多個(gè) JobDetail 和 Trigger。當(dāng) Trigger 與 JobDetail 組合,就可以被 Scheduler 容器調(diào)度了。
二、SpringBoot 使用 Quartz
2.1、基本步驟
基本步驟就那些,這篇也不是高大上講原理和流程之類的,就是偏向?qū)嵅?,可能一些地方在代碼中含有注釋,就不再貼說(shuō)明了~
基本:JDK 8、SpringBoot、MybatisPlus、Quartz
創(chuàng)建一個(gè) SpringBoot 項(xiàng)目
導(dǎo)入相關(guān)依賴~
?<parent> ? ? ?<groupId>org.springframework.boot</groupId> ? ? ?<artifactId>spring-boot-starter-parent</artifactId> ? ? ?<version>2.5.2</version> ? ? ?<relativePath/> ?</parent> ?<properties> ? ? ?<java.version>1.8</java.version> ? ? ?<maven.compiler.source>8</maven.compiler.source> ? ? ?<maven.compiler.target>8</maven.compiler.target> ?</properties> ?<dependencies> ? ? ?<dependency> ? ? ? ? ?<groupId>org.springframework.boot</groupId> ? ? ? ? ?<artifactId>spring-boot-starter-web</artifactId> ? ? ?</dependency> ? ? ?<dependency> ? ? ? ? ?<groupId>org.springframework.boot</groupId> ? ? ? ? ?<artifactId>spring-boot-starter-quartz</artifactId> ? ? ?</dependency> ? ? ?<dependency> ? ? ? ? ?<groupId>org.projectlombok</groupId> ? ? ? ? ?<artifactId>lombok</artifactId> ? ? ?</dependency> ? ? ?<dependency> ? ? ? ? ?<groupId>mysql</groupId> ? ? ? ? ?<artifactId>mysql-connector-java</artifactId> ? ? ?</dependency> ? ? ?<dependency> ? ? ? ? ?<groupId>com.baomidou</groupId> ? ? ? ? ?<artifactId>mybatis-plus-boot-starter</artifactId> ? ? ? ? ?<version>3.4.1</version> ? ? ?</dependency> ? ? ?<dependency> ? ? ? ? ?<groupId>cn.hutool</groupId> ? ? ? ? ?<artifactId>hutool-all</artifactId> ? ? ? ? ?<version>5.1.4</version> ? ? ?</dependency> ? ? ?<dependency> ? ? ? ? ?<groupId>com.alibaba</groupId> ? ? ? ? ?<artifactId>fastjson</artifactId> ? ? ? ? ?<version>1.2.76</version> ? ? ?</dependency> ?</dependencies>
項(xiàng)目結(jié)構(gòu):
2.2、執(zhí)行 Quartz 需要的SQL文件
找到 quartz 需要的 sql 文件,在數(shù)據(jù)庫(kù)中執(zhí)行,這也是Quartz持久化的基礎(chǔ)~
往下滑,找到你需要的sql文件即可。
執(zhí)行完的結(jié)果:
在此基礎(chǔ)上,我們?cè)兕~外增加一張表,與我們可能有業(yè)務(wù)關(guān)聯(lián)的信息整合,這啥啥允許為空,是方便我寫(xiě)測(cè)試~,并非正例
DROP TABLE IF EXISTS `sys_quartz_job`; CREATE TABLE `sys_quartz_job` ( `id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `create_by` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '創(chuàng)建人', `create_time` datetime NULL DEFAULT NULL COMMENT '創(chuàng)建時(shí)間', `del_flag` int(1) UNSIGNED ZEROFILL NULL DEFAULT 0 COMMENT '刪除狀態(tài)', `update_by` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '修改人', `update_time` datetime NULL DEFAULT NULL COMMENT '修改時(shí)間', `job_class_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '任務(wù)類名', `cron_expression` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'cron表達(dá)式', `parameter` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '參數(shù)', `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '描述', `status` int(1) NULL DEFAULT NULL COMMENT '狀態(tài) 0正常 -1停止', PRIMARY KEY (`id`) USING BTREE ) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
2.3、Controller
我們直接從controller說(shuō)起吧,從上往下開(kāi)發(fā)。
其實(shí)一旦牽扯到表的操作,我們無(wú)疑就是crud四件事。
?/** ? * @Description: 定時(shí)任務(wù)在線管理 ? * @author nzc ? */ ?@RestController ?@RequestMapping("/quartzJob") ?@Slf4j ?public class QuartzJobController { ? @Autowired ? private IQuartzJobService quartzJobService; ? @Autowired ? private Scheduler scheduler; ? @RequestMapping(value = "/list", method = RequestMethod.GET) ? public Result<?> queryPageList(QuartzJob quartzJob, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, ? ? @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize, HttpServletRequest req) { ? Page<QuartzJob> page = new Page<QuartzJob>(pageNo, pageSize); ? IPage<QuartzJob> pageList = quartzJobService.page(page); ? ? ? ? ?return Result.ok(pageList); ? } ? @RequestMapping(value = "/add", method = RequestMethod.POST) ? public Result<?> add(@RequestBody QuartzJob quartzJob) { List<QuartzJob> list = quartzJobService.list(new QueryWrapper<QuartzJob>().eq("job_class_name", quartzJob.getJobClassName())); ? if (list != null && list.size() > 0) { ? return Result.error("該定時(shí)任務(wù)類名已存在"); ? } ? quartzJobService.saveAndScheduleJob(quartzJob); ? return Result.ok("創(chuàng)建定時(shí)任務(wù)成功"); ? } ? @RequestMapping(value = "/edit", method = RequestMethod.PUT) ? public Result<?> eidt(@RequestBody QuartzJob quartzJob) { ? try { ? quartzJobService.editAndScheduleJob(quartzJob); ? } catch (SchedulerException e) { ? log.error(e.getMessage(),e); ? return Result.error("更新定時(shí)任務(wù)失敗!"); ? } ? ? ?return Result.ok("更新定時(shí)任務(wù)成功!"); ? } ? @RequestMapping(value = "/delete", method = RequestMethod.DELETE) ? public Result<?> delete(@RequestParam(name = "id", required = true) String id) { ? QuartzJob quartzJob = quartzJobService.getById(id); ? if (quartzJob == null) { ? return Result.error("未找到對(duì)應(yīng)實(shí)體"); ? } ? quartzJobService.deleteAndStopJob(quartzJob); ? ? ? ? ?return Result.ok("刪除成功!"); ? } ? @RequestMapping(value = "/deleteBatch", method = RequestMethod.DELETE) ? public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) { ? if (ids == null || "".equals(ids.trim())) { ? return Result.error("參數(shù)不識(shí)別!"); ? } ? for (String id : Arrays.asList(ids.split(","))) { ? QuartzJob job = quartzJobService.getById(id); ? quartzJobService.deleteAndStopJob(job); ? } ? ? ? ? ?return Result.ok("刪除定時(shí)任務(wù)成功!"); ? } ? /** ? * 暫停定時(shí)任務(wù) ? * @param jobClassName ? */ ? @GetMapping(value = "/pause") ? public Result<Object> pauseJob(@RequestParam(name = "jobClassName", required = true) String jobClassName) { ? QuartzJob job = null; ? try { ? job = quartzJobService.getOne(new LambdaQueryWrapper<QuartzJob>().eq(QuartzJob::getJobClassName, jobClassName)); ? if (job == null) { ? return Result.error("定時(shí)任務(wù)不存在!"); ? } ? scheduler.pauseJob(JobKey.jobKey(jobClassName.trim())); ? } catch (SchedulerException e) { ? throw new MyException("暫停定時(shí)任務(wù)失敗"); ? } ? job.setStatus(CommonConstant.STATUS_DISABLE); ? quartzJobService.updateById(job); ? return Result.ok("暫停定時(shí)任務(wù)成功"); ? } ? /** ? * 恢復(fù)定時(shí)任務(wù) ? * @param jobClassName ? */ ? @GetMapping(value = "/resume") ? public Result<Object> resumeJob(@RequestParam(name = "jobClassName", required = true) String jobClassName) { ? QuartzJob job = quartzJobService.getOne(new LambdaQueryWrapper<QuartzJob>().eq(QuartzJob::getJobClassName, jobClassName)); ? if (job == null) { ? return Result.error("定時(shí)任務(wù)不存在!"); ? } ? quartzJobService.resumeJob(job); ? //scheduler.resumeJob(JobKey.jobKey(job.getJobClassName().trim())); ? return Result.ok("恢復(fù)定時(shí)任務(wù)成功"); ? } ? /** 通過(guò)id查詢*/ ? @RequestMapping(value = "/queryById", method = RequestMethod.GET) ? public Result<?> queryById(@RequestParam(name = "id", required = true) String id) { ? QuartzJob quartzJob = quartzJobService.getById(id); ? ? ? ? ?return Result.ok(quartzJob); ? } ?}
2.4、Service 劃重點(diǎn)
?public interface IQuartzJobService extends IService<QuartzJob> { ? boolean saveAndScheduleJob(QuartzJob quartzJob); ? boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException; ? boolean deleteAndStopJob(QuartzJob quartzJob); ? boolean resumeJob(QuartzJob quartzJob); ?}
其中最主要的實(shí)現(xiàn)都是在這里:
?@Slf4j ?@Service ?public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob> implements IQuartzJobService { ? @Autowired ? private QuartzJobMapper quartzJobMapper; ? @Autowired ? private Scheduler scheduler; ? /**保存&啟動(dòng)定時(shí)任務(wù)*/ ? @Override ? public boolean saveAndScheduleJob(QuartzJob quartzJob) { ? if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) { ? // 定時(shí)器添加 ? this.schedulerAdd(quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter()); ? } ? // DB設(shè)置修改 ? return this.save(quartzJob); ? } ? /**恢復(fù)定時(shí)任務(wù) */ ? @Override ? public boolean resumeJob(QuartzJob quartzJob) { ? schedulerDelete(quartzJob.getJobClassName().trim()); ? schedulerAdd(quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter()); ? quartzJob.setStatus(CommonConstant.STATUS_NORMAL); ? return this.updateById(quartzJob); ? } ? /**編輯&啟停定時(shí)任務(wù) @throws SchedulerException */ ? @Override ? public boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException { ? if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) { ? schedulerDelete(quartzJob.getJobClassName().trim()); ? schedulerAdd(quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter()); ? }else{ ? scheduler.pauseJob(JobKey.jobKey(quartzJob.getJobClassName().trim())); ? } ? return this.updateById(quartzJob); ? } ? /**刪除&停止刪除定時(shí)任務(wù)*/ ? @Override ? public boolean deleteAndStopJob(QuartzJob job) { ? schedulerDelete(job.getJobClassName().trim()); ? return this.removeById(job.getId()); ? } ? /** 添加定時(shí)任務(wù)*/ ? private void schedulerAdd(String jobClassName, String cronExpression, String parameter) { ? try { ? // 啟動(dòng)調(diào)度器 ? scheduler.start(); ? // 構(gòu)建job信息 ? JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobClassName).usingJobData("parameter", parameter).build(); ? // 表達(dá)式調(diào)度構(gòu)建器(即任務(wù)執(zhí)行的時(shí)間) ? CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression); ? // 按新的cronExpression表達(dá)式構(gòu)建一個(gè)新的trigger ? CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName).withSchedule(scheduleBuilder).build(); ? scheduler.scheduleJob(jobDetail, trigger); ? } catch (SchedulerException e) { ? throw new MyException("創(chuàng)建定時(shí)任務(wù)失敗", e); ? } catch (RuntimeException e) { ? throw new MyException(e.getMessage(), e); ? }catch (Exception e) { ? throw new MyException("后臺(tái)找不到該類名:" + jobClassName, e); ? } ? } ? /** 刪除定時(shí)任務(wù)*/ ? private void schedulerDelete(String jobClassName) { ? try { ? /*使用給定的鍵暫停Trigger 。*/ ? scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName)); ? /*從調(diào)度程序中刪除指示的Trigger */ ? scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName)); ? /*從 Scheduler 中刪除已識(shí)別的Job - 以及任何關(guān)聯(lián)的Trigger */ ? scheduler.deleteJob(JobKey.jobKey(jobClassName)); ? } catch (Exception e) { ? log.error(e.getMessage(), e); ? throw new MyException("刪除定時(shí)任務(wù)失敗"); ? } ? } ? private static Job getClass(String classname) throws Exception { ? Class<?> class1 = Class.forName(classname); ? return (Job) class1.newInstance(); ? } ?}
?@Mapper ?public interface QuartzJobMapper extends BaseMapper<QuartzJob> { ?}
2.5、實(shí)體類
?@Data ?@TableName("sys_quartz_job") ?public class QuartzJob implements Serializable { ? ? @TableId(type = IdType.ID_WORKER_STR) ? ? private String id; ? ? private String createBy; ? ? private String updateBy; ? ? /**任務(wù)類名*/ ? ? private String jobClassName; ? ? /** cron表達(dá)式 */ ? ? private String cronExpression; ? ? /** 參數(shù)*/ ? ? private String parameter; ? ? private String description; ? ? /** 狀態(tài) 0正常 -1停止*/ ? ? private Integer status; ? ? @TableLogic ? ? private Integer delFlag; ? ? @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") ? ? @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") ? ? @TableField(fill = FieldFill.INSERT) ? private Date createTime; ? ? @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") ? ? @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") ? ? @TableField(fill = FieldFill.INSERT_UPDATE) ? ? private Date updateTime; ?}
另外在這里順帶補(bǔ)充一下,本項(xiàng)目在yml中配置quartz,如下:
spring: ## quartz定時(shí)任務(wù),采用數(shù)據(jù)庫(kù)方式 quartz: job-store-type: jdbc
2.6、簡(jiǎn)單的 Job 案例
如果調(diào)度器要執(zhí)行任務(wù),首先得要有一個(gè)任務(wù)相關(guān)滴類。
寫(xiě)了兩個(gè)平常的案例,一個(gè)是不帶參數(shù)的,一個(gè)是帶參數(shù)的。
/** * 不帶參的簡(jiǎn)單定時(shí)任務(wù) * @Author nzc */ @Slf4j public class SampleJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { log.info(String.format("Ning zaichun的 普通定時(shí)任務(wù) SampleJob ! 時(shí)間:" + new Date())); } }
帶參數(shù)的:
?/** ? * 帶參數(shù)的簡(jiǎn)單的定時(shí)任務(wù) ? * @Author nzc ? */ ?@Slf4j ?public class SampleParamJob implements Job { ? /** ? * 若參數(shù)變量名修改 QuartzJobController中也需對(duì)應(yīng)修改 ? */ ? private String parameter; ? public void setParameter(String parameter) { ? this.parameter = parameter; ? } ? @Override ? public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { ? log.info(String.format("welcome %s! Jeecg-Boot 帶參數(shù)定時(shí)任務(wù) SampleParamJob ! ? 時(shí)間:" + LocalDateTime.now(), this.parameter)); ? } ?}
2.7、那么該如何使用呢?
啟動(dòng)項(xiàng)目,讓我們拿起來(lái)postman來(lái)測(cè)試吧,康康該如何使用,數(shù)據(jù)表在使用的時(shí)候,又有怎么樣的變化~
我們直接來(lái)測(cè)試添加定時(shí)任務(wù)的接口,先來(lái)個(gè)不用參數(shù)的吧
?{ ? ? ?"createBy": "nzc", ? ? ?"jobClassName": "com.nzc.quartz.job.SampleJob", ? ? ?"cronExpression": "0/10 * * * * ? ", ? ? ?"description": "每十秒執(zhí)行一次", ? ? ?"status": "0" ?}
添加完之后就已經(jīng)在執(zhí)行了。
此時(shí)我們將項(xiàng)目停止,重新啟動(dòng)~
調(diào)度器也會(huì)主動(dòng)去檢測(cè)任務(wù)信息,如果有,就會(huì)開(kāi)始執(zhí)行。
我們?cè)賮?lái)測(cè)測(cè)帶有參數(shù)的
也是可以成功的,并且也是按照我們?cè)O(shè)定的時(shí)間執(zhí)行的
其他的接口也是同樣如此,根據(jù)接口的設(shè)定,將參數(shù)傳入即可
到此這篇關(guān)于SpringBoot 整合 Quartz 定時(shí)任務(wù)框架詳解的文章就介紹到這了,更多相關(guān)SpringBoot 整合 Quartz 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- springboot整合x(chóng)xl-job實(shí)現(xiàn)分布式定時(shí)任務(wù)的過(guò)程
- SpringBoot整合Quartz實(shí)現(xiàn)定時(shí)任務(wù)詳解
- springboot整合Quartz實(shí)現(xiàn)動(dòng)態(tài)配置定時(shí)任務(wù)的方法
- 詳解SpringBoot開(kāi)發(fā)案例之整合定時(shí)任務(wù)(Scheduled)
- springboot整合quartz實(shí)現(xiàn)定時(shí)任務(wù)示例
- SpringBoot定時(shí)任務(wù)兩種(Spring Schedule 與 Quartz 整合 )實(shí)現(xiàn)方法
- SpringBoot整合定時(shí)任務(wù)的方法
相關(guān)文章
Java中@Autowired和@Resource區(qū)別
本文主要介紹了Java中@Autowired和@Resource區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06一些java二進(jìn)制的相關(guān)基礎(chǔ)知識(shí)
這篇文章主要介紹了一些java二進(jìn)制的相關(guān)基礎(chǔ)知識(shí),在Java語(yǔ)言中byte代表最小計(jì)量單位,byte由8位2進(jìn)制數(shù)組成。,需要的朋友可以參考下2019-06-06解決SpringBoot運(yùn)行報(bào)錯(cuò):找不到或無(wú)法加載主類的問(wèn)題
這篇文章主要介紹了解決SpringBoot運(yùn)行報(bào)錯(cuò):找不到或無(wú)法加載主類的問(wèn)題,具有很好的參考價(jià)值,對(duì)大家的學(xué)習(xí)或工作有一定的參考價(jià)值,需要的朋友可以參考下2023-09-09使用Jenkins配置Git+Maven的自動(dòng)化構(gòu)建的方法
這篇文章主要介紹了使用Jenkins配置Git+Maven的自動(dòng)化構(gòu)建的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01Java分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)原理與用法詳解
這篇文章主要介紹了Java分支結(jié)構(gòu)和循環(huán)結(jié)構(gòu)原理與用法,結(jié)合實(shí)例形式分析了java分支結(jié)構(gòu)、循環(huán)結(jié)構(gòu)、跳轉(zhuǎn)語(yǔ)句等相關(guān)概念、原理、使用技巧與操作注意事項(xiàng),需要的朋友可以參考下2020-02-02Spring boot 無(wú)法注入service問(wèn)題
這篇文章主要介紹了Spring boot 無(wú)法注入service問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10SpringCloud Eureka自我保護(hù)機(jī)制原理解析
這篇文章主要介紹了SpringCloud Eureka自我保護(hù)機(jī)制原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02