SpringBoot程序預裝載數(shù)據(jù)的實現(xiàn)方法及實踐
簡介
在項目實際的開發(fā)過程中,有時候會遇到需要在應用程序啟動完畢對外提供服務之前預先將部分數(shù)據(jù)裝載到緩存的需求。本文就總結(jié)了常見的數(shù)據(jù)預裝載方式及其實踐。
適用場景
- 預裝載應用級別數(shù)據(jù)到緩存:如字典數(shù)據(jù)、公共的業(yè)務數(shù)據(jù)
- 系統(tǒng)預熱
- 心跳檢測:如在系統(tǒng)啟動完畢訪問一個外服務接口等場景
常用方法
- ApplicationEvent
- CommandLineRunner
- ApplicationRunner
ApplicationEvent
應用程序事件,就是發(fā)布訂閱模式。在系統(tǒng)啟動完畢,向應用程序注冊一個事件,監(jiān)聽者一旦監(jiān)聽到了事件的發(fā)布,就可以做一些業(yè)務邏輯的處理了。
既然是發(fā)布-訂閱模式,那么訂閱者既可以是一個,也可以是多個。
定義event
import org.springframework.context.ApplicationEvent;
public class CacheEvent extends ApplicationEvent {
public CacheEvent(Object source) {
super(source);
}
}定義listener
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@Component
public class CacheEventListener implements ApplicationListener<CacheEvent> {
@Autowired
private MaskingService maskingService;
@Autowired
private RedisCache redisCache;
@Override
public void onApplicationEvent(CacheEvent cacheEvent) {
log.debug("CacheEventListener-start");
List<SysMasking> maskings = maskingService.selectAllSysMaskings();
if (!CollectionUtils.isEmpty(maskings)) {
log.debug("CacheEventListener-data-not-empty");
Map<String, List<SysMasking>> cacheMap = maskings.stream().collect(Collectors.groupingBy(SysMasking::getFieldKey));
cacheMap.keySet().forEach(x -> {
if (StringUtils.isNotEmpty(x)) {
log.debug("CacheEventListener-x={}", x);
List<SysMasking> list = cacheMap.get(x);
long count = redisCache.setCacheList(RedisKeyPrefix.MASKING.getPrefix() + x, list);
log.debug("CacheEventListener-count={}", count);
} else {
log.debug("CacheEventListener-x-is-empty");
}
});
} else {
log.debug("CacheEventListener-data-is-empty");
}
log.debug("CacheEventListener-end");
}
}
注冊event
@Slf4j
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class BAMSApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(BAMSApplication.class, args);
log.debug("app-started");
context.publishEvent(new CacheEvent("處理緩存事件"));
}
}CommandLineRunner
通過實現(xiàn) CommandLineRunner 接口,可以在應用程序啟動完畢,回調(diào)到指定的方法中。
package com.ramble.warmupservice.runner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class CacheCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
log.debug("CacheCommandLineRunner-start");
log.debug("CacheCommandLineRunner-參數(shù)={}", args);
// 注入業(yè)務 service ,獲取需要緩存的數(shù)據(jù)
// 注入 redisTemplate ,將需要緩存的數(shù)據(jù)存放到 redis 中
log.debug("CacheCommandLineRunner-end");
}
}
ApplicationRunner
同CommandLineRunner 類似,區(qū)別在于,對參數(shù)做了封裝。
package com.ramble.warmupservice.runner;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class CacheApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
log.debug("CacheApplicationRunner-start");
log.debug("CacheApplicationRunner-參數(shù)={}", JSON.toJSONString(args));
// 注入業(yè)務 service ,獲取需要緩存的數(shù)據(jù)
// 注入 redisTemplate ,將需要緩存的數(shù)據(jù)存放到 redis 中
log.debug("CacheApplicationRunner-end");
}
}測試
上述代碼在idea中啟動,若不帶參數(shù),輸出如下:
2022-04-28 15:44:00.981 INFO 1160 --- [ main] c.r.w.WarmupServiceApplication : Started WarmupServiceApplication in 1.335 seconds (JVM running for 2.231)
2022-04-28 15:44:00.982 DEBUG 1160 --- [ main] c.r.w.runner.CacheApplicationRunner : CacheApplicationRunner-start
2022-04-28 15:44:01.025 DEBUG 1160 --- [ main] c.r.w.runner.CacheApplicationRunner : CacheApplicationRunner-參數(shù)={"nonOptionArgs":[],"optionNames":[],"sourceArgs":[]}
2022-04-28 15:44:01.025 DEBUG 1160 --- [ main] c.r.w.runner.CacheApplicationRunner : CacheApplicationRunner-end
2022-04-28 15:44:01.025 DEBUG 1160 --- [ main] c.r.w.runner.CacheCommandLineRunner : CacheCommandLineRunner-start
2022-04-28 15:44:01.026 DEBUG 1160 --- [ main] c.r.w.runner.CacheCommandLineRunner : CacheCommandLineRunner-參數(shù)={}
2022-04-28 15:44:01.026 DEBUG 1160 --- [ main] c.r.w.runner.CacheCommandLineRunner : CacheCommandLineRunner-end
2022-04-28 15:44:01.026 DEBUG 1160 --- [ main] c.r.w.listener.CacheEventListener : CacheEventListener-start
2022-04-28 15:44:01.026 DEBUG 1160 --- [ main] c.r.w.listener.CacheEventListener : CacheEventListener-參數(shù)=ApplicationEvent-->緩存系統(tǒng)數(shù)據(jù)
2022-04-28 15:44:01.029 DEBUG 1160 --- [ main] c.r.w.listener.CacheEventListener : CacheEventListener-end
Disconnected from the target VM, address: '127.0.0.1:61320', transport: 'socket'
Process finished with exit code 130
若使用 java -jar xxx.jar --server.port=9009 啟動,則輸入如下:
2022-04-28 16:02:05.327 INFO 9916 --- [ main] c.r.w.WarmupServiceApplication : Started WarmupServiceApplication in 1.78 seconds (JVM running for 2.116)
2022-04-28 16:02:05.329 DEBUG 9916 --- [ main] c.r.w.runner.CacheApplicationRunner : CacheApplicationRunner-start
2022-04-28 16:02:05.393 DEBUG 9916 --- [ main] c.r.w.runner.CacheApplicationRunner : CacheApplicationRunner-參數(shù)={"nonOptionArgs":[],"optionNames":["server.port"],"sourceArgs":["--server.port=9009"]}
2022-04-28 16:02:05.395 DEBUG 9916 --- [ main] c.r.w.runner.CacheApplicationRunner : CacheApplicationRunner-end
2022-04-28 16:02:05.395 DEBUG 9916 --- [ main] c.r.w.runner.CacheCommandLineRunner : CacheCommandLineRunner-start
2022-04-28 16:02:05.395 DEBUG 9916 --- [ main] c.r.w.runner.CacheCommandLineRunner : CacheCommandLineRunner-參數(shù)=--server.port=9009
2022-04-28 16:02:05.395 DEBUG 9916 --- [ main] c.r.w.runner.CacheCommandLineRunner : CacheCommandLineRunner-end
2022-04-28 16:02:05.395 DEBUG 9916 --- [ main] c.r.w.listener.CacheEventListener : CacheEventListener-start
2022-04-28 16:02:05.396 DEBUG 9916 --- [ main] c.r.w.listener.CacheEventListener : CacheEventListener- 參數(shù)=ApplicationEvent-->緩存系統(tǒng)數(shù)據(jù)
2022-04-28 16:02:05.396 DEBUG 9916 --- [ main] c.r.w.listener.CacheEventListener : CacheEventListener-end
執(zhí)行順序
從上面測試的輸出,可以看到三種方式執(zhí)行的順序為:
ApplicationRunner--->CommandLineRunner--->ApplicationEvent
另外,若同時定義多個runner,可以通過order來指定他們的優(yōu)先級。
代碼
https://gitee.com/naylor_personal/ramble-spring-cloud/tree/master/warmup-service
到此這篇關于SpringBoot程序預裝載數(shù)據(jù)的文章就介紹到這了,更多相關SpringBoot預裝載數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java創(chuàng)建多線程異步執(zhí)行實現(xiàn)代碼解析
這篇文章主要介紹了Java創(chuàng)建多線程異步執(zhí)行實現(xiàn)代碼解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-07-07
Spring中的NamespaceHandler加載過程源碼詳解
這篇文章主要介紹了Spring中的NamespaceHandler加載過程源碼詳解,Spring提供的NamespaceHandler的處理機制,簡單來說就是命名空間處理器,Spring為了開放性提供了NamespaceHandler機制,這樣我們就可以根據(jù)需求自己來處理我們設置的標簽元素,需要的朋友可以參考下2024-02-02
IntelliJ IDEA 好用插件之a(chǎn)nalyze inspect code詳解
這篇文章主要介紹了IntelliJ IDEA 好用插件之a(chǎn)nalyze inspect code的相關知識,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2020-12-12
源碼解析Spring 數(shù)據(jù)庫異常抽理知識點總結(jié)
在本篇文章里小編給大家分享了關于源碼解析Spring 數(shù)據(jù)庫異常抽理知識點內(nèi)容,對此有需要的朋友們學習參考下。2019-05-05
如何在IDEA運行spark程序(搭建Spark開發(fā)環(huán)境)
spark程序可以通過pom.xml的文件配置,添加spark-core依賴,可以直接在IDEA中編寫spark程序并運行結(jié)果,這篇文章主要介紹了如何在IDEA運行spark程序(搭建Spark開發(fā)環(huán)境),需要的朋友可以參考下2024-02-02
Spring AspectJ 實現(xiàn)AOP的方法你了解嗎
這篇文章主要為大家介紹了Spring AspectJ 實現(xiàn)AOP的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-01-01

