spring boot使用Jedis整合Redis實現快取(AOP)
目錄
一:環境準備
1:準備Redis環境
使用redis做快取的話,需要有redis服務,可以將服務部署在遠端伺服器上,也可以部署到本機上。
1.1. 部署在linux伺服器
1.1.1安裝Redis
#安裝redis,當前最新的版本是redis-5.0.0.tar.gz,可以通過http://download.redis.io/releases地址檢視最新版本
$ wget http://download.redis.io/releases/redis-5.0.0.tar.gz
$ tar xzf redis-5.0.0.tar.gz
$ cd redis-5.0.0
$ make
1.1.2啟動Redis服務並使用
#啟動redis服務
$ cd src
$ ./redis-server
#使用redis客戶端測試redis
$ cd src
$ ./redis-cli
redis> set testkey testvalue
OK
redis> get testkey
"testvalue"
如果上述過程沒有報錯的話,那麼恭喜你啟動redis服務成功,下面我們將會使用jedis操作redis來實現快取
1.2. 部署在windows伺服器
2.1下載redis壓縮包
下載zip壓縮包(Redis-x64-*.zip):https://github.com/MSOpenTech/redis/releases
將其解壓到某一資料夾中,重新命名為Redis
2.2啟動redis服務並使用
開啟cmd,切換到解壓的Redis資料夾中,執行如下命令,
會發現出現”The server is now ready to accept connections on port 6379“字樣表示啟動成功
redis-server.exe redis.windows.conf
再開啟一個cmd,
原來的cmd不要關閉,保持開啟狀態
,輸入以下命令:
其中:127.0.0.1:為你的redis服務ip地址,如果是本機安裝的就是127.0.0.1
,埠6379是redis預設監聽的埠
redis-cli.exe -h 127.0.0.1 -p 6379
#如果redis設定了密碼,可以新增引數-a指定密碼,例如:
redis-cli.exe -h 127.0.0.1 -p 6379 -a 12345
可以使用redis命令測試是否可以正常使用,至此redis服務便準備完畢了~
2:準備專案環境
- 首先spring boot專案,當然不是boot專案也可以,我是以boot專案舉例的
- pom檔案新增依賴,只列出了此功能設計特殊所需的
<!--jedis依賴-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!--用於序列化 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
- application.yml新增配置,如果你是xml格式的檔案,yml格式和xml格式類似,只是yml格式更加明瞭一些,google一下轉換一下格式就行
spring:
jedis:
max:
total: 1000 #jedis總量
idle: 50 #空閒jedis例項最大值
waitmillis: 100 #等待時間
timout: 100
active: 1000 # 最大活躍數量jedis例項
host: 127.0.0.1 # redis服務ip地址
port: 6379 # 埠
password: test # redis密碼
至此,環境配置完成了,現在只需要操作redis實現快取了~~
二:快取功能實現
1:過程簡介
- 對於不加快取的專案,我們每一次的請求都會去資料庫中查詢,即使兩次請求一樣並且獲取的資料一樣,也是會去查詢資料庫,這就造成了資料庫資源的浪費,並且如果併發量特別高的話,資料庫的壓力太大,容易造成查詢緩慢、資料庫當機、查詢失敗等問題。
- 專案新增快取之後,請求查詢資料的時候會先查詢快取,快取(這裡指只有一級快取)中沒有才會到達資料庫。相同的請求在快取還沒有過期 的情況下,會得到快取中的資料並返回,不會到達資料庫,這樣做即減少了資料庫的壓力提高了併發量又提升了查詢速度。
- 流程圖:
2:程式碼實現與介紹
2.1.執行過程
- 請求到達Controller中的介面時,因為我們在CacheAspect類中配置的切入點包含這個介面,所以進入CacheAspect類的doAround方法中執行快取操作
- 在doAround中,首先獲取key,判斷redis中是否包含key,包含就返回快取中的資料,完成請求
- 不包含就執行呼叫的介面通過查詢資料庫獲取資料,並將其快取到redis中,完成一次請求不包含就執行呼叫的介面通過查詢資料庫獲取資料,並將其快取到redis中,完成請求
2.2. 組成部分與實現
- 自定義註解:NeedCacheAop
用在方法上面標識呼叫該方法的請求需要被快取
其中的nxxx、expx、time等引數是為了可以更靈活的空值快取的方式與過期時間,具體含義請看下面”其他“中的set方法引數解析
/**
* 自定義註解,用於標識方法是否需要使用快取
*/
@Target({ElementType.PARAMETER, ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NeedCacheAop {
//代表快取策咯,nx:代表key不存在再進行快取kv,xx:代表key存在再進行快取kv 預設為"不存在key快取key"
String nxxx() default "nx";
//代表過期時間單位,ex:秒 px:毫秒 預設為"秒"
String expx() default "ex";
//過期時間
long time() default 30*60;
}
- 序列化工具類:SerializeUtil
使用FastJso對要快取的資料進行序列化後儲存與獲取快取中的反序列化
使用fastjson對資料進行序列化與反序列化,非常簡單
public class SerializeUtil {
private static Logger logger = LoggerFactory.getLogger("SerializeUtil");
public static String serializeObject(Object obj){
logger.info("serialize object :"+obj);
String jsonObj = JSON.toJSONString(obj);
return jsonObj;
}
public static JSONObject unserializeObject(String serobj){
logger.info("unserialize object :"+serobj);
JSONObject jsonObj = JSON.parseObject(serobj);
return jsonObj;
}
}
- 操作快取service類:CacheService介面 與其實現類 CacheServiceImpl
方法內部封裝了關於快取的get set containKey getKeyAop等方法
public interface CacheService {
/**獲取jedis例項*/
Jedis getResource() throws Exception;
/**設定key與value*/
void set(String key, String value, String nxxx, String expx, long time);
/**根據key獲取value*/
String get(String key);
/**判斷是否存在key*/
boolean containKey(String key);
/**釋放jedis例項資源*/
void returnResource(Jedis jedis);
/**獲取key*/
String getKeyForAop(JoinPoint joinPoint, HttpServletRequest request);
}
@Service
public class CacheServiceImpl implements CacheService {
private static Logger logger = LoggerFactory.getLogger(CacheServiceImpl.class);
@Autowired
private JedisPool jedisPool;
/**獲取jedis例項*/
public Jedis getResource() throws Exception{
return jedisPool.getResource();
}
/**設定key與value*/
public void set(String key, String value,String nxxx,String expx,long time) {
Jedis jedis=null;
try{
jedis = getResource();
jedis.set(key,value,nxxx,expx,time);
} catch (Exception e) {
logger.error("Redis set error: "+ e.getMessage() +" - " + key + ", value:" + value);
}finally{
returnResource(jedis);
}
}
/**根據key獲取value*/
public String get(String key) {
String result = null;
Jedis jedis=null;
try{
jedis = getResource();
result = jedis.get(key);
} catch (Exception e) {
logger.error("Redis set error: "+ e.getMessage() +" - " + key + ", value:" + result);
}finally{
returnResource(jedis);
}
return result;
}
/**判斷是否存在key*/
public boolean containKey(String key){
boolean b;
Jedis jedis = null;
try{
jedis = getResource();
b = jedis.exists(key);
return b;
}catch (Exception e){
logger.error("Redis server error::"+e.getMessage());
return false;
}finally {
returnResource(jedis);
}
}
/**釋放jedis例項資源*/
public void returnResource(Jedis jedis) {
if(jedis != null){
jedis.close();
}
}
/**獲取key*/
public String getKeyForAop(JoinPoint joinPoint, HttpServletRequest request){
//獲取引數的序列化
Object[] objects = joinPoint.getArgs();
String args = SerializeUtil.serializeObject(objects[0]);
//獲取請求url
String url = request.getRequestURI();
//獲取請求的方法
String method = request.getMethod();
//獲取當前日期,規避預設init情況
String date = LocalDate.now().toString();
//key值獲取
return args + url + method + date;
}
}
- 切面類:CacheAspect
用於對相應的請求介面切入快取存取的相關邏輯,使用AOP可以對程式碼0侵入性,是一個很好的方法
@Component
@Aspect
public class CacheAspect {
@Autowired
CacheService cacheService;
/**設定切入點*/
//方法上面有@NeedCacheAop的方法,增加靈活性
@Pointcut("@annotation(com.xcar.data.web.backend.util.annotation.NeedCacheAop)")
public void annotationAspect(){}
//相應包下所有以XcarIndex開頭的類中的所有方法,減少程式碼侵入性
@Pointcut("execution(public * com.xcar.data.web.backend.controller.XcarIndex*.*(..))")
public void controllerAspect(){}
/**環繞通知*/
@Around(value = "controllerAspect()||annotationAspect()")
public Object doAround(ProceedingJoinPoint joinPoint){
//獲取請求
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
.getRequestAttributes()).getRequest();
//儲存介面返回值
Object object = new Object();
//獲取註解對應配置過期時間
NeedCacheAop cacheAop = ((MethodSignature)joinPoint.getSignature()).getMethod().getAnnotation(NeedCacheAop.class); //獲取註解自身
String nxxx;String expx;long time;
if (cacheAop == null){//規避使用第二種切點進行快取操作的情況
nxxx = "nx";
expx = "ex";
time = 30*60; //預設過期時間為30分鐘
}else{
nxxx = cacheAop.nxxx();
expx = cacheAop.expx();
time = cacheAop.time();
}
//獲取key
String key = cacheService.getKeyForAop(joinPoint,request);
if (cacheService.containKey(key)){
String obj = cacheService.get(key);
if ("fail".endsWith(obj)){ //規避redis服務不可用
try {
//執行介面呼叫的方法
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}else{
JSONObject klass = SerializeUtil.unserializeObject(obj);
return new ResponseEntity<>(klass.get("body"), HttpStatus.OK) ;
}
}else{
try {
////執行介面呼叫的方法並獲取返回值
object = joinPoint.proceed();
String serobj = SerializeUtil.serializeObject(object);
cacheService.set(key,serobj,nxxx,expx,time);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
return object;
}
}
- jedis配置類:JedisConfiguration
用於配置JedisPool的相關引數,與建立JedisPool物件,便於後面注入使用
@Configuration
public class JedisConfiguration extends CachingConfigurerSupport {
private Logger logger = LoggerFactory.getLogger(JedisConfiguration.class);
@Value("${spring.jedis.port}")
private Integer port;
@Value("${spring.jedis.host}")
private String host;
@Value("${spring.jedis.max.total}")
private Integer maxTotal;
@Value("${spring.jedis.max.idle}")
private Integer maxIdle;
@Value("${spring.jedis.max.waitmillis}")
private Long maxWaitMillis;
@Value("${spring.jedis.password}")
private String password;
public JedisConfiguration() {}
/**設定*/
@Bean
public JedisPool redisPoolFactory(){
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
jedisPoolConfig.setMaxTotal(maxTotal);
JedisPool jedisPool = new JedisPool(jedisPoolConfig,host,port,1000,password);
logger.info("JedisPool build success!");
logger.info("Redis host:" + host + ":" + port);
return jedisPool;
}
//下面屬性是get set方法省略
}
- 請求資料物件
請求資料封裝的物件,用於組成key,這個物件應該
- 響應資料物件
響應的資料物件,快取就是對其進行序列化後快取
該物件類一定繼承Serializable介面,使其可被序列化,例如:
public class XcarIndexCarAttentionIndexResponse implements Serializable{
priate List<BaseChartsResponse.Line> lines = new ArrayList<>();
private Series_DateBubble series_datebubble = new Series_DateBubble();
private String flag = "1";
public Series_DateBubble getSeries_datebubble() {
if (series_datebubble == null) {
series_datebubble = new Series_DateBubble();
}
return series_datebubble;
}
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
public void setSeries_datebubble(Series_DateBubble series_datebubble) {
this.series_datebubble = series_datebubble;
}
public List<BaseChartsResponse.Line> getLines() {
return lines;
}
public void setLines(List<BaseChartsResponse.Line> lines) {
this.lines = lines;
}
public class Series_DateBubble {
private List<BaseChartsResponse.Series_DateBubble> datas = new ArrayList<>();
private String[] dataRange = {};
public List<BaseChartsResponse.Series_DateBubble> getDatas() {
return datas;
}
public void setDatas(List<BaseChartsResponse.Series_DateBubble> datas) {
this.datas = datas;
}
public String[] getDataRange() {
return dataRange;
}
public void setDataRange(String[] dataRange) {
this.dataRange = dataRange;
}
}
}
- 其他:
我們要新增快取的Controller介面的實現,例如:我要切入的介面
package com.xcar.data.web.backend.controller;
.....
@RequestMapping(value = "/page/trend", method = RequestMethod.POST)
public ResponseEntity<XcarIndexCarIntentionIndexResponse> getTrendPage(@RequestBody XcarIndexCarIntentionIndexRequest ro, HttpServletRequest request) throws Exception {
XcarIndexCarIntentionIndexResponse res = new XcarIndexCarIntentionIndexResponse();
try {
res = delegate.getTrendPage(ro);
} catch (Exception e) {
throw e;
}
return new ResponseEntity(res, HttpStatus.OK);
}
三:其他相關
3.1.jedis中set方法引數:
- key :快取的key值
- value :快取的value值
- nxxx: NX|XX兩種選擇, NX – 快取不存在時才進行快取. XX – 快取存在時再進行快取
- expx :EX|PX兩種選擇, 過期時間的代為,EX 代表秒; PX 代表毫秒
- time :過期時間的數值
3.2.AOP面向切面程式設計
AOP(Aspect Oriented Programing):面向切面程式設計,將通用的邏輯從業務邏輯中分離出來。AOP把軟體系統分為兩個部分:核心關注點和橫切關注點。業務處理的主要流程是核心關注點,與之關係不大的部分是橫切關注點。橫切關注點的一個特點是,他們經常發生在核心關注點的多處,而各處都基本相似。比如許可權認證、日誌、事務處理。Aop 的作用在於分離系統中的各種關注點,將核心關注點和橫切關注點分離開來。正如Avanade公司的高階方案構架師Adam Magee所說,AOP的核心思想就是“將應用程式中的商業邏輯同對其提供支援的通用服務進行分離”。
相關概念:
- 連線點(Joinpoint): 表示需要在程式中插入橫切關注點的擴充套件點,連線點可能是類初始化、方法執行、方法呼叫、欄位呼叫或處理異常等等,Spring只支援方法執行連線點;在AOP中表示為“在哪裡幹”;
- 切入點(Pointcut): 選擇一組相關連線點的模式,即可以認為連線點的集合,Spring支援perl5正規表示式和AspectJ切入點模式,Spring預設使用AspectJ語法;在AOP中表示為“在哪裡乾的集合”;
- 通知(Advice): 在連線點上執行的行為,通知提供了在AOP中需要在切入點所選擇的連線點處進行擴充套件現有行為的手段;包括前置通知(before advice)、後置通知(after advice)、環繞通知(around advice),在Spring中通過代理模式實現AOP,並通過攔截器模式以環繞連線點的攔截器鏈織入通知;在AOP中表示為“幹什麼”;
- 切面(Aspect):橫切關注點的模組化,比如日誌元件。可以認為是通知、引入和切入點的組合;在Spring中可以使用Schema和@AspectJ方式進行組織實現;在AOP中表示為“在哪乾和幹什麼集合”;
- 引入(Introduction): 也稱為內部型別宣告,為已有的類新增額外新的欄位或方法,Spring允許引入新的介面(必須對應一個實現)到所有被代理物件(目標物件);在AOP中表示為“幹什麼(引入什麼)”;
- 目標物件(Target Object):需要被織入橫切關注點的物件,即該物件是切入點選擇的物件,需要被通知的物件,從而也可稱為“被通知物件”;由於Spring AOP 通過代理模式實現,從而這個物件永遠是被代理物件;在AOP中表示為“對誰幹”;
- AOP代理(AOP Proxy): AOP框架使用代理模式建立的物件,從而實現在連線點處插入通知(即應用切面),就是通過代理來對目標物件應用切面。在Spring中,AOP代理可以用JDK動態代理或CGLIB代理實現,而通過攔截器模型應用切面。
- 織入(Weaving): 織入是一個過程,是將切面應用到目標物件從而建立出AOP代理物件的過程,織入可以在編譯期、類裝載期、執行期進行。組裝方面來建立一個被通知物件。這可以在編譯時完成(例如使用AspectJ編譯器),也可以在執行時完成。Spring和其他純Java AOP框架一樣,在執行時完成織入。
3.3.AOP中切點表示式(來自:http://blog.51cto.com/5914679/2092253)
切點指示符
切點指示符是切點定義的關鍵字,切點表示式以切點指示符開始。開發人員使切點指示符來告訴切點將要匹配什麼,有以下9種切點指示符:execution、within、this、target、args、@target、@args、@within、@annotation,下面一一介結這9種切點指示符。
execution
execution是一種使用頻率比較高比較主要的一種切點指示符,用來匹配方法簽名,方法簽名使用全限定名,包括訪問修飾符(public/private/protected)、返回型別,包名、類名、方法名、引數,其中返回型別,包名,類名,方法,引數是必須的,如下面程式碼片段所示:
@Pointcut(“execution(public String org.baeldung.dao.FooDao.findById(Long))”)
上面的程式碼片段裡的表示式精確地匹配到FooDao類裡的findById(Long)方法,但是這看起來不是很靈活。假設我們要匹配FooDao類的所有方法,這些方法可能會有不同的方法名,不同的返回值,不同的引數列表,為了達到這種效果,我們可以使用萬用字元。如下程式碼片段所示:
@Pointcut(“execution(* org.baeldung.dao.FooDao.*(…))”)
第一個萬用字元匹配所有返回值型別,第二個匹配這個類裡的所有方法,()括號表示引數列表,括號裡的用兩個點號表示匹配任意個引數,包括0個
within
使用within切點批示符可以達到上面例子一樣的效果,within用來限定連線點屬於某個確定型別的類。如下面程式碼的效果與上面的例子是一樣的:
@Pointcut(“within(org.baeldung.dao.FooDao)”)
我們也可以使用within指示符來匹配某個包下面所有類的方法(包括子包下面的所有類方法),如下程式碼所示:
@Pointcut(“within(org.baeldung…*)”)
this 和 target
this用來匹配的連線點所屬的物件引用是某個特定型別的例項,target用來匹配的連線點所屬目標物件必須是指定型別的例項;那麼這兩個有什麼區別呢?原來AspectJ在實現代理時有兩種方式:
1、如果當前物件引用的型別沒有實現自介面時,spring aop使用生成一個基於CGLIB的代理類實現切面程式設計
2、如果當前物件引用實現了某個介面時,Spring aop使用JDK的動態代理機制來實現切面程式設計
this指示符就是用來匹配基於CGLIB的代理類,通俗的來講就是,如果當前要代理的類物件沒有實現某個介面的話,則使用this;target指示符用於基於JDK動態代理的代理類,通俗的來講就是如果當前要代理的目標物件有實現了某個介面的話,則使用target.:
public class FooDao implements BarDao {
…
}
比如在上面這段程式碼示例中,spring aop將使用jdk的動態代理來實現切面程式設計,在編寫匹配這型別的目標物件的連線點表示式時要使用target指示符, 如下所示:
@Pointcut(“target(org.baeldung.dao.BarDao)”)
如果FooDao類沒有實現任何介面,或者在spring aop配置屬性:proxyTargetClass設為true時,Spring Aop會使用基於CGLIB的動態位元組碼技為目標物件生成一個子類將為代理類,這時應該使用this指示器:
@Pointcut(“this(org.baeldung.dao.FooDao)”)
引數
引數指示符是一對括號所括的內容,用來匹配指定方法引數:
@Pointcut(“execution(* …find(Long))”)
這個切點匹配所有以find開頭的方法,並且只一個Long類的引數。如果我們想要匹配一個有任意個引數,但是第一個引數必須是Long類的,我們這可使用下面這個切點表示式:
@Pointcut(“execution(* …find(Long,…))”)
@Target
這個指示器匹配指定連線點,這個連線點所屬的目標物件的類有一個指定的註解:
@Pointcut("@target(org.springframework.stereotype.Repository)")
@args
這個指示符是用來匹配連線點的引數的,@args指出連線點在執行時傳過來的引數的類必須要有指定的註解,假設我們希望切入所有在執行時接受實@Entity註解的bean物件的方法:
@Pointcut("@args(org.baeldung.aop.annotations.Entity)")
public void methodsAcceptingEntities() {}
為了在切面裡接收並使用這個被@Entity的物件,我們需要提供一個引數給切面通知:JointPoint:
@Before(“methodsAcceptingEntities()”)
public void logMethodAcceptionEntityAnnotatedBean(JoinPoint jp) {
logger.info("Accepting beans with @Entity annotation: " + jp.getArgs()[0]);
}
@within
這個指示器,指定匹配必須包括某個註解的的類裡的所有連線點:
@Pointcut("@within(org.springframework.stereotype.Repository)")
上面的切點跟以下這個切點是等效的:
@Pointcut(“within(@org.springframework.stereotype.Repository *)”)
@annotation
這個指示器匹配那些有指定註解的連線點,比如,我們可以新建一個這樣的註解@Loggable:
@Pointcut("@annotation(org.baeldung.aop.annotations.Loggable)")
public void loggableMethods() {}
我們可以使用@Loggable註解標記哪些方法執行需要輸出日誌:
@Before(“loggableMethods()”)
public void logMethod(JoinPoint jp) {
String methodName = jp.getSignature().getName();
logger.info("Executing method: " + methodName);
}
切點表示式組合
可以使用&&、||、!、三種運算子來組合切點表示式,表示與或非的關係。
@Pointcut("@target(org.springframework.stereotype.Repository)")
public void repositoryMethods() {}
@Pointcut(“execution(* …create(Long,…))”)
public void firstLongParamMethods() {}
@Pointcut(“repositoryMethods() && firstLongParamMethods()”)
public void entityCreationMethods() {}
參考blog:
https://blog.csdn.net/u012050154/article/details/77370297
http://blog.51cto.com/5914679/2092253
相關文章
- Spring AOP整合redis(註解方式) 實現快取統一管理SpringRedis快取
- spring-boot-route(十二)整合redis做為快取SpringbootRedis快取
- 高手如何處理快取:SpringBoot整合Redis實現快取處理(AOP技術)!快取Spring BootRedis
- Spring Boot Cache Redis快取Spring BootRedis快取
- Spring Boot整合Spring AopSpring Boot
- 搞懂分散式技術14:Spring Boot使用註解整合Redis快取分散式Spring BootRedis快取
- SpringBoot快取管理(二) 整合Redis快取實現Spring Boot快取Redis
- 15.SpringBoot整合Redis快取實現Spring BootRedis快取
- 另一種快取,Spring Boot 整合 Ehcache快取Spring Boot
- Spring Boot整合Redis實戰操作Spring BootRedis
- Spring Boot整合RedisSpring BootRedis
- Spring Boot 整合redisSpring BootRedis
- 從零搭建Spring Boot腳手架(6):整合Redis作為快取Spring BootRedis快取
- Spring Boot整合Hazelcast實現叢集與分散式記憶體快取Spring BootAST分散式記憶體快取
- Spring Boot + Redis 快取方案深度解讀Spring BootRedis快取
- Spring Boot利用AOP獲取使用者操作實現日誌記錄Spring Boot
- 在Kubernetes上使用Spring Boot實現Hazelcast分散式快取 – PiotrSpring BootAST分散式快取
- SpringBoot中使用Redis實現快取Spring BootRedis快取
- 使用Spring Boot實現Redis事務 | VinsguruSpring BootRedis
- Spring-Boot整合RedisSpringbootRedis
- spring boot(三)整合 redisSpring BootRedis
- 【Azure Redis 快取】示例使用 redisson-spring-boot-starter 連線/使用 Azure Redis 服務Redis快取Springboot
- Spring-boot整合AOP及AOP相關學習Springboot
- springboot整合redis2.x,使用spring註解進行快取Spring BootRedis快取
- 分散式快取綜合指南:Kubernetes + Redis + Spring Boot分散式快取RedisSpring Boot
- 5、Spring Boot快取Spring Boot快取
- SpringBoot整合Redis快取Spring BootRedis快取
- Spring Boot 專案整合RedisSpring BootRedis
- Spring Boot 2.x基礎教程:使用集中式快取RedisSpring Boot快取Redis
- Spring Boot:簡單使用EhCache快取框架Spring Boot快取框架
- Springboot 整合 SpringCache 使用 Redis 作為快取Spring BootGCRedis快取
- 使用Spring Boot實現資料庫整合配置案例Spring Boot資料庫
- Spring boot學習(六)Spring boot實現AOP記錄操作日誌Spring Boot
- Spring-Boot專案中配置redis註解快取SpringbootRedis快取
- WEB 應用快取解析以及使用 Redis 實現分散式快取Web快取Redis分散式
- [Redis 客戶端整合] SpringBoot 整合 JedisRedis客戶端Spring Boot
- Spring Boot整合MyBatis實現通用MapperSpring BootMyBatisAPP
- Spring Boot 如何快速整合 Redis 哨兵?Spring BootRedis