手寫[email protected]註解 支援過期時間設定
-
原理解釋
@Cacheable註解作用,將帶有該註解方法的返回值存放到redis中;
使用方法在方法上使用@Cacheable(key=”test+#p0+#p1....”)
表示key值為test+方法第一個引數+方法第二個引數,value值為該方法的返回值。
以下源程式碼表示獲取人員列表,redis中存放的key值為‘leader’+leaderGroupId+uuid+yearDetailId
@Override @Cacheable(key="'leader'+#p0+#p1+#p2",value="leader") public List<Leader> listLeaders(String leaderGroupId, String uuid, String yearDetailId) { return sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId); }
等同於
@Override public List<Leader> listLeaders(String leaderGroupId, String uuid, String yearDetailId) { String key = "leader" + leaderGroupId + uuid + yearDetailId; // 判斷快取是否存在redis中 boolean hasKey = redisUtil.hasKey(key); if (hasKey) { //如果存在 返還redis中的值 Object leadersList = redisUtil.get(key); return (List<Leader>) leadersList; } else { List<Leader> leadersQuotaDetailList = sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId); //將查詢結果存放在redis中 redisUtil.set(key, leadersQuotaDetailList); return leadersQuotaDetailList; } }
說白了就是在原方法的前面判斷key值是否存在redis中,如果存在就取記憶體中的值,如果不存在就查詢資料庫,將查詢結果存放在redis中。
-
實現方法
- 使用代理模式,在方法執行前和執行後可以新增其他處理程式,本文采用springAOP+註解方式。
- 整合redis,封裝redis工具類
- 原版本不支援key過期時間設定,本文將實現
-
原始碼
快取配置類 RedisConfig
package com.huajie.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; /** * Redis快取配置類 */ @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.timeout}") private int timeout; // 自定義快取key生成策略 @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, java.lang.reflect.Method method, Object... params) { StringBuffer sb = new StringBuffer(); sb.append(target.getClass().getName()); sb.append(method.getName()); for (Object obj : params) { sb.append(obj.toString()); } return sb.toString(); } }; } // 快取管理器 @Bean public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); // 設定快取過期時間 cacheManager.setDefaultExpiration(10000); return cacheManager; } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(factory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key採用String的序列化方式 template.setKeySerializer(stringRedisSerializer); // hash的key也採用String的序列化方式 template.setHashKeySerializer(stringRedisSerializer); // value序列化方式採用jackson template.setValueSerializer(jackson2JsonRedisSerializer); // hash的value序列化方式採用jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } private void setSerializer(StringRedisTemplate template) { @SuppressWarnings({ "rawtypes", "unchecked" }) Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); template.setValueSerializer(jackson2JsonRedisSerializer); } }
redis依賴引入,配置檔案,工具類RedisUtil ,網上幾個版本都類似,本文參考以下版本傳送門
準備工作做好之後開始正式編寫註解@Cacheable nextkey()用做二級快取 本文中不會用到
建立java註解@ExtCacheable
package com.huajie.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtCacheable {
String key() default "";
String nextKey() default "";
int expireTime() default 1800;//30分鐘
}
SpringAop切面 CacheableAspect
package com.huajie.aspect;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.huajie.annotation.ExtCacheable;
import com.huajie.utils.RedisUtil;
/**
* redis快取處理
* 不適用與內部方法呼叫(this.)或者private
*/
@Component
@Aspect
public class CacheableAspect {
@Autowired
private RedisUtil redisUtil;
@Pointcut("@annotation(com.huajie.annotation.ExtCacheable)")
public void annotationPointcut() {
}
@Around("annotationPointcut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// 獲得當前訪問的class
Class<?> className = joinPoint.getTarget().getClass();
// 獲得訪問的方法名
String methodName = joinPoint.getSignature().getName();
// 得到方法的引數的型別
Class<?>[] argClass = ((MethodSignature) joinPoint.getSignature()).getParameterTypes();
Object[] args = joinPoint.getArgs();
String key = "";
int expireTime = 1800;
try {
// 得到訪問的方法物件
Method method = className.getMethod(methodName, argClass);
method.setAccessible(true);
// 判斷是否存在@ExtCacheable註解
if (method.isAnnotationPresent(ExtCacheable.class)) {
ExtCacheable annotation = method.getAnnotation(ExtCacheable.class);
key = getRedisKey(args,annotation);
expireTime = getExpireTime(annotation);
}
} catch (Exception e) {
throw new RuntimeException("redis快取註解引數異常", e);
}
// 獲取快取是否存在
boolean hasKey = redisUtil.hasKey(key);
if (hasKey) {
return redisUtil.get(key);
} else {
//執行原方法(java反射執行method獲取結果)
Object res = joinPoint.proceed();
//設定快取
redisUtil.set(key, res);
//設定過期時間
redisUtil.expire(key, expireTime);
return res;
}
}
private int getExpireTime(ExtCacheable annotation) {
return annotation.expireTime();
}
private String getRedisKey(Object[] args,ExtCacheable annotation) {
String primalKey = annotation.key();
//獲取#p0...集合
List<String> keyList = getKeyParsList(primalKey);
for (String keyName : keyList) {
int keyIndex = Integer.parseInt(keyName.toLowerCase().replace("#p", ""));
Object parValue = args[keyIndex];
primalKey = primalKey.replace(keyName, String.valueOf(parValue));
}
return primalKey.replace("+","").replace("'","");
}
// 獲取key中#p0中的引數名稱
private static List<String> getKeyParsList(String key) {
List<String> ListPar = new ArrayList<String>();
if (key.indexOf("#") >= 0) {
int plusIndex = key.substring(key.indexOf("#")).indexOf("+");
int indexNext = 0;
String parName = "";
int indexPre = key.indexOf("#");
if(plusIndex>0){
indexNext = key.indexOf("#") + key.substring(key.indexOf("#")).indexOf("+");
parName = key.substring(indexPre, indexNext);
}else{
parName = key.substring(indexPre);
}
ListPar.add(parName.trim());
key = key.substring(indexNext + 1);
if (key.indexOf("#") >= 0) {
ListPar.addAll(getKeyParsList(key));
}
}
return ListPar;
}
}
業務模組使用方法
@Override
@ExtCacheable(key = "Leaders+#p0+#p1+#p2")
// 手機端獲取領導人員列表
public List<Leader> listLeaders(String leaderGroupId, String uuid, String yearDetailId) {
List<Leader> leadersQuotaDetailList = sysIndexMapper.listLeaders(leaderGroupId, uuid, yearDetailId);
return leadersQuotaDetailList;
}
業務模組過期時間使用方法,5分鐘過期
@Override
@ExtCacheable(key = "mobileCacheFlag", expireTime = 60 * 5)
public int cacheFlag() {
int mobileCacheFlag = 1;
mobileCacheFlag = sysIndexMapper.cacheFlag();
return mobileCacheFlag;
}
redis截圖
相關推薦
手寫<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="96e4f3f2ffe5d6d5f7f5fef3f7f4faf3">[email160;protected]a>註解 支援過期時間設定
原理解釋 @Cacheable註解作用,將帶有該註解方法的返回值存放到redis中; 使用方法在方法上使用@Cacheable(key=”test+#p0+#p1....”) 表示key值為test+方法第一個引數+方法第二個引數,value值為該方法的返回值。
手寫<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="92e0f7f6fbe1d2d1f3f1faf7f3f0fef7">[email160;protected]a>註解 引數java物件作為ke
1.實現方式說明 本文在---- 手寫redis @ Cacheable註解支援過期時間設定 的基礎之上進行擴充套件。 1.1問題說明: @ Cacheable(key = “'leader'+#p0 +#p1 +#p2” )一般用法,#p0表示方法的第一個引數,#p1表示
手寫<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bdcfd8d9d4cefdfedcded5d8dcdfd1d8">[email160;protected]a>註解 支援過期時間設定
原理解釋 友情連結 手寫redis @ Cacheable註解引數java物件作為鍵值 @Cacheable註解作用,將帶有該註解方法的返回值存放到redis的的中; 使用方法在方法上使用@Cacheable(鍵=“測試+#P0 + P1
用VS2010寫了一個串列埠示例程式(使用API寫的)<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="371a1a1a1a5b5e59535655525b5b77">[email160;protec
為了配合GNSS的調式,今天用VS2010寫了一個串列埠示例程式(使用API寫的)。#include "MySerial.h" #include <TCHAR.H> #include &l
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2770424e7f4e49785d4d4a404b5e676e73">[email160;protected]a>@雲墨文玩手串
Redis的危險命令主要有: flushdb,清空資料庫 flushall,清空所有記錄,資料庫 config,客戶端連線後可配置伺服器 keys,客戶端連線後可檢視所有存在的鍵 作為服務端的redis-server,我們常常需要禁用以上命令來使伺服器更加安全。 禁用的具
shell腳本中的$# $0 <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f8dcb8">[email160;protected]a> $* $$ $! $?的意義
腳本 $* width 上一個 pre shell int .cn height 轉載自:http://www.cnblogs.com/davygeek/p/5670212.html 今天學寫腳本遇到一些變量不認識,在此做下記錄。 變量 含義 $0 當前腳本的文件
shell中$*與<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b296f2">[email160;protected]a>的區別
劃分 位置 一個 這也 差異 獨立 [email protected] 情況 雙引號 $*所有的位置參數,被作為一個單詞 註意:"$*"必須被""引用 [email protected] 與$*同義,但是每個參數都是一個獨立的""引用字串,這就意味著參數
Spring4.0系列<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="aa9f87eae9c5c4cec3dec3c5c4cbc6">[email160;protected]a>
one window 標識 cto ace ted ada bsp 布爾 這篇文章介紹Spring 4的@Conditional註解。在Spring的早期版本你可以通過以下方法來處理條件問題: 3.1之前的版本,使用Spring Expression Langua
Spring高級話題<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b29ff2f7dcd3d0ded7">[email160;protected]a>***註解的工作原理
sso metadata bool logs tcl task ota -c ann 出自:http://blog.csdn.net/qq_26525215 @EnableAspectJAutoProxy @EnableAspectJAutoProxy註解 激活Aspe
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="297a595b40474e69685c5d465e405b4c4d">[email160;protected]a>註解與自動裝配(轉發)
配置 調用方法 support autowired 信息 ann over 反射機制 test 1 配置文件的方法我們編寫spring 框架的代碼時候。一直遵循是這樣一個規則:所有在spring中註入的bean 都建議定義成私有的域變量。並且要配套寫上 get 和 se
linux bash Shell特殊變數:Shell $0, $#, $*, <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8aaeca">[email160;protected]a>, $?
在linux下配置shell引數說明 前面已經講到,變數名只能包含數字、字母和下劃線,因為某些包含其他字元的變數有特殊含義,這樣的變數被稱為特殊變數。 例如,$ 表示當前Shell程序的ID,即pid,看下面的程式碼: [[email protected] /]$ ec
spring <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="62000d0d16222103010a0703000e07">[email160;protected]a>中value的理解
先看原始碼 /** * Names of the caches in which method invocation results are stored. * <p>Names may be used to determine the target cache (or cac
{<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="733e3c3f3f2a342136363d203323213c273c3d3e323a3f5d303c3e">[email160;protecte
近日,復旦解密安全團隊發現GandCrab4.0活躍度提升,跟蹤到多起GandCrab4.0變種勒索事件,現釋出安全預警,提醒廣大使用者預防GandCrab4.0勒索。 目前復旦解密已經可以成功解密GandCrab4.0變種採用RSA+AES加密演算法 mg中毒檔案可以在一個小時解決.電話151691214
Springboot註解<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="260b0b666549485254494a4a4354">[email160;protected]a>和@RestCon
1.使用@Controller 註解,在對應的方法上,檢視解析器可以解析return 的jsp,html頁面,並且跳轉到相應頁面;若返回json等內容到頁面,則需要加@ResponseBody註解 [email protected]註解,相當於@[email protected
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5b2c3e391b33">[email160;protected]a>,c小總結
問題0:元素內聯元素,行內元素,行內塊元素. 內聯: 寬高M,P都有效 行內元素:無寬高,內容撐開,M,P左右有效
SQL Server資料庫mdf檔案中了勒索病毒<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fc9f8e858c889998a39d8f9d9293bc9f939f97">[email160;p
SQL,資料庫,勒索病毒,mdf檔案中毒,[email protected]_email *SQL Server資料庫mdf檔案中了勒索病毒[email protected]_email。副檔名變為[email protected]_email SQL Serv
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="5400313a273b2632383b2379142032">[email160;protected]a>_export詳解
Tensorflow經常看到定義的函式前面加了“@tf_export”。例如,tensorflow/python/platform/app.py中有: @tf_export('app.run') def run(main=None, argv=None): """Runs the progr
手把手教你搭建React Native 開發環境 - ios篇 (React <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="eda38c99849b88adddc3d8d8c3d9">[email
由於之前我是h5的,沒接觸過ios和安卓, 也不瞭解xcode配置,所以 建議學reace-native之前還是先去了解一下ios和安卓開發環境搭建等問題。 環境下載及配置 nodejs:https://nodejs.org/en/download/ 設定淘寶映象 $ npm con
<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4978382833093e3a3179797878">[email160;protected]a>
function changeSpan(){ var f = document.getElementById("file1").files; &nb
SpringBoot學習<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="b7e8f7e7c5d8c7d2c5c3cee4d8c2c5d4d2">[email160;protected]a>&am
文章目錄 @PropertySource:載入指定的配置檔案 @ImportResource:匯入Spring的配置檔案,讓配置檔案裡面的內容生效; @Bean @PropertySource:載入指定的配置檔案