如何打造redis緩存組件
更新時(shí)間:2024年12月09日 17:08:38 作者:阿花落知多少
文章介紹了如何使用熱插拔AOP、反射、Redis自定義注解和SpringEL表達(dá)式來打造一個(gè)優(yōu)雅的Redis緩存組件,通過這種方式,可以重構(gòu)和簡化緩存代碼,并提供了Redis配置和自定義注解的詳細(xì)說明,文章還包含了AOP測試的總結(jié),并鼓勵(lì)讀者參考和支持
打造redis緩存組件
使用熱插拔aop+反射+redis自定義注解+spring EL表達(dá)式打造redis緩存組件,優(yōu)雅重構(gòu)緩存代碼
redis配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableAspectJAutoProxy //V2 開啟AOP自動(dòng)代理
public class RedisConfig
{
/**
* @param lettuceConnectionFactory
* @return
*
* redis序列化的工具配置類,下面這個(gè)請一定開啟配置
* 127.0.0.1:6379> keys *
* 1) "ord:102" 序列化過
* 2) "\xac\xed\x00\x05t\x00\aord:102" 野生,沒有序列化過
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory)
{
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
//設(shè)置key序列化方式string
redisTemplate.setKeySerializer(new StringRedisSerializer());
//設(shè)置value的序列化方式j(luò)son
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}自定義注解
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 MyRedisCache //@EnableAspectJAutoProxy //啟AOP自動(dòng)代理
{
//約等于鍵的前綴prefix,
String keyPrefix();
//SpringEL表達(dá)式,解析占位符對應(yīng)的匹配value值
String matchValue();
}AOP
import jakarta.annotation.Resource;
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.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
import java.util.Objects;
@Component
@Aspect
public class MyRedisCacheAspect
{
@Resource
private RedisTemplate redisTemplate;
//配置織入點(diǎn)
@Pointcut("@annotation(com.atguigu.interview2.annotations.MyRedisCache)")
public void cachePointCut(){}
@Around("cachePointCut()")
public Object doCache(ProceedingJoinPoint joinPoint)
{
Object result = null;
/**
* @MyRedisCache(keyPrefix = "user",matchValue = "#id")
* public User getUserById(Integer id)
* {
* return userMapper.selectByPrimaryKey(id);
* }
*/
try
{
//1 獲得重載后的方法名
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
//2 確定方法名后獲得該方法上面配置的注解標(biāo)簽MyRedisCache
MyRedisCache myRedisCacheAnnotation = method.getAnnotation(MyRedisCache.class);
//3 拿到了MyRedisCache這個(gè)注解標(biāo)簽,獲得該注解上面配置的參數(shù)進(jìn)行封裝和調(diào)用
String keyPrefix = myRedisCacheAnnotation.keyPrefix();
String matchValueSpringEL = myRedisCacheAnnotation.matchValue();
//4 SpringEL 解析器
ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(matchValueSpringEL);//#id
EvaluationContext context = new StandardEvaluationContext();
//5 獲得方法里面的形參個(gè)數(shù)
Object[] args = joinPoint.getArgs();
DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
String[] parameterNames = discoverer.getParameterNames(method);
for (int i = 0; i < parameterNames.length; i++)
{
System.out.println("獲得方法里參數(shù)名和值: "+parameterNames[i] + "\t" + args[i].toString());
context.setVariable(parameterNames[i], args[i].toString());
}
//6 通過上述,拼接redis的最終key形式
String key = keyPrefix + ":" + expression.getValue(context).toString();
System.out.println("------拼接redis的最終key形式: " + key);
//7 先去redis里面查詢看有沒有
result = redisTemplate.opsForValue().get(key);
if (result != null)
{
System.out.println("------redis里面有,我直接返回結(jié)果不再打擾mysql: " + result);
return result;
}
//8 redis里面沒有,去找msyql查詢或叫進(jìn)行后續(xù)業(yè)務(wù)邏輯
//-------aop精華部分,才去找findUserById方法干活
//userMapper.selectByPrimaryKey(id);
result = joinPoint.proceed();//主業(yè)務(wù)邏輯查詢mysql,放行放行放行
//9 mysql步驟結(jié)束,還需要把結(jié)果存入redis一次,緩存補(bǔ)償
if (result != null)
{
System.out.println("------redis里面無,還需要把結(jié)果存入redis一次,緩存補(bǔ)償: " + result);
redisTemplate.opsForValue().set(key, result);
}
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return result;
}
}測試
/**
* 會(huì)將返回值存進(jìn)redis里,key生成規(guī)則需要程序員用SpEL表達(dá)式自己指定,value就是程序從mysql查出并返回的user
* redis的key 等于 keyPrefix:matchValue
*/
@Override
@MyRedisCache(keyPrefix = "user",matchValue = "#id")
public User getUserById(Integer id)
{
return userMapper.selectByPrimaryKey(id);
}總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
CentOS下Redis數(shù)據(jù)庫的基本安裝與配置教程
這篇文章主要介紹了CentOS下Redis數(shù)據(jù)庫的基本安裝與配置教程,Redis一般被用作基于內(nèi)存的緩存式數(shù)據(jù)存儲(chǔ),要的朋友可以參考下2015-12-12
Redis過期Key刪除策略和內(nèi)存淘汰策略的實(shí)現(xiàn)
當(dāng)內(nèi)存使用達(dá)到上限,就無法存儲(chǔ)更多數(shù)據(jù)了,為了解決這個(gè)問題,Redis內(nèi)部會(huì)有兩套內(nèi)存回收的策略,過期Key刪除策略和內(nèi)存淘汰策略,本文就來詳細(xì)的介紹一下這兩種方法,感興趣的可以了解一下2024-02-02
RedisTemplate中boundHashOps的使用小結(jié)
redisTemplate.boundHashOps(key)?是 RedisTemplate 類的一個(gè)方法,本文主要介紹了RedisTemplate中boundHashOps的使用小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2024-04-04
使用Redis命令操作數(shù)據(jù)庫的常見錯(cuò)誤及解決方法
由于Redis是內(nèi)存數(shù)據(jù)庫,因此可能會(huì)存在一些安全問題,下面這篇文章主要給大家介紹了關(guān)于使用Redis命令操作數(shù)據(jù)庫的常見錯(cuò)誤及解決方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-02-02

