打造分布式缓存组件【场景】

avatar
作者
筋斗云
阅读量:0

本文将采用AOP + 反射 + Redis自定义缓存标签,重构缓存代码,打造基础架构分布式缓存组件

配置

需要在Redis配置类中开启AOP自动代理,即通过==@EnableAspectJAutoProxy ==注解实现该功能

import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cache.CacheManager; 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.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.Primary; import org.springframework.data.redis.cache.RedisCacheConfiguration; 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.serializer.*;  import java.lang.reflect.Method; import java.time.Duration;  /**  * Redis配置类  *  */ @Configuration @EnableCaching @EnableAspectJAutoProxy // 开启AOP自动代理 public class RedisConfig {     @Bean     @Primary     public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {         RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();         redisTemplate.setConnectionFactory(redisConnectionFactory);          //String的序列化方式         StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();         // 使用GenericJackson2JsonRedisSerializer 替换默认序列化(默认采用的是JDK序列化)         GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();          //序列号key value         redisTemplate.setKeySerializer(stringRedisSerializer);         redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);         redisTemplate.setHashKeySerializer(stringRedisSerializer);         redisTemplate.setHashValueSerializer(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 BaizeRedisCache {      // redis的key前缀     String keyPrefix();      // SpringEL表达式,解析占位符对应的匹配value值     String matchValue();  } 

定义Redis缓存组件切面类

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.aspectj.lang.reflect.MethodSignature; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.expression.Expression; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.stereotype.Component;  import java.lang.reflect.Method;  /**  * @Description:redis缓存组件切面类  * @Author: smart  * @Date: 2024/8/7 8:40  */ @Aspect @Component public class BaizeRedisCacheAspect {      @Resource     private RedisTemplate redisTemplate;      // 配置织入点     @Pointcut("@annotation(com.atguigu.daijia.common.config.redis.BaizeRedisCache)")     public void cachePoint(){}      @Around("cachePoint()")     public Object doCache(ProceedingJoinPoint joinPoint){         // TODO         Object result = null;          try{             // 1、获取重载后的方法名             MethodSignature signature = (MethodSignature) joinPoint.getSignature();             Method method = signature.getMethod();              // 2、确定方法名上配置的注解标签             BaizeRedisCache baizeRedisCache = method.getAnnotation(BaizeRedisCache.class);              // 3、获得该注解标签上配置的参数进行封装和调用             String keyPrefix = baizeRedisCache.keyPrefix();             String matchValueSpringEL = baizeRedisCache.matchValue();              // 4、SpringEL解析器             SpelExpressionParser parser = new SpelExpressionParser();             Expression expression = parser.parseExpression(matchValueSpringEL);              StandardEvaluationContext context = new StandardEvaluationContext();              // 5、获得方法里的形参个数             Object[] args = joinPoint.getArgs();             DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();             String[] parameterNames = discoverer.getParameterNames(method);             for (int i = 0; i < parameterNames.length; i++) {                 System.out.println("获得方法里参数名和值: " + 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){                 // 若redis存在则直接返回结果,无需到数据库中查询                 return result;             }              // 8、redis中没有则去数据库中查询             result = joinPoint.proceed();              // 9、主业务逻辑查询完之后,将数据存入redis             if (result != null){                 redisTemplate.opsForValue().set(key, result);             }          }catch (Throwable throwable){             throwable.printStackTrace();         }          return result;     } } 

应用

在这里插入图片描述

    广告一刻

    为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!