• Redis缓存系列--(五)自定义Redis缓存注解的使用


    自定义Redis缓存注解的实现

    我们在Spring的框架中,可以使用注解的形式(@EnableCache和@Cacheable)来实现对查询的数据进行Redis的缓存,我们自己其实也可以自定义一个缓存注解来实现redis缓存的功能。

    编写自定义缓存注解

    首先,我们要自定义一个Redis缓存注解,之后要将该注解标注到对应的方法上去,代码如下:

    /**
     * 对方法启用Redis缓存,使其具有方法前判断缓存,方法后如果没有缓存则存储Redis缓存
     * 缓存key的格式为:value::key,具体的数值由用户传递的注解参数来提供
     * @author young
     */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MyRedisCacheable {
        /**
         * Redis缓存key的前缀
         * @return
         */
        String value() default "";
    
        /**
         * Redis缓存key的后缀
         * @return
         */
        String key() default "";
    }
    

    编写具体AOP代理方法类

    注解只是用来标注当前的方法要用来做什么,同时传递相应操作所需要的参数信息。具体要在标注的方法前后实现什么功能,还需要通过Spring AOP的面向切面编程来实现对方法前后所需要进行的处理。具体代码如下:

    /**
     * MyRedisCacheable注解的具体处理类,实现对标注方法执行前做Redis缓存检查处理,方法执行后执行缓存Redis数据的处理
     * @author young
     */
    @Component
    @Aspect
    public class CacheAspect {
        private Logger logger =  LoggerFactory.getLogger(CacheAspect.class);
    
        @Autowired
        private RedisTemplate redisTemplate;
    
        /**
         * 设置注解的切入点,即指定切入的方法为
         */
        @Pointcut("@annotation(com.young.redis.aop.MyRedisCacheable)")
        public void cachePointcut(){
    
        }
    
        /**
         * 定义需要进行AOP切面编程的切点是哪个,也即标注MyRedisCacheable注释的方法
         * @param proceedingJoinPoint 当前切入方法的上下文
         * @return
         */
        @Around("cachePointcut()")
        public Object doRedisCache(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            Object value = null;
            try {
                //获取切入方法的标签
                MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
                //通过该标签来获取修饰的方法和方法参数
                Method method = proceedingJoinPoint.getTarget().getClass().
                        getMethod(signature.getName(),signature.getMethod().getParameterTypes());
                //获取当前方法的注解以及注解的参数
                MyRedisCacheable myRedisCacheable = method.getAnnotation(MyRedisCacheable.class);
                //redis key的EL表达式
                String keyEL = myRedisCacheable.key();
                //redis key的前缀
                String prifix = myRedisCacheable.value();
    
                //解析EL表达式
                ExpressionParser expressionParser = new SpelExpressionParser();
                Expression expression =expressionParser.parseExpression(keyEL);
    
                //用来组合EL表达式和方法参数的EL上下文对象
                EvaluationContext evaluationContext = new StandardEvaluationContext();
    
                //获取方法的参数,将参数放入evaluationContext
                Object[] args = proceedingJoinPoint.getArgs();
                DefaultParameterNameDiscoverer defaultParameterNameDiscoverer = new DefaultParameterNameDiscoverer();
                String[] parameterNames = defaultParameterNameDiscoverer.getParameterNames(method);
                for (int i = 0; i < parameterNames.length; i++) {
                    evaluationContext.setVariable(parameterNames[i],args[i].toString());
                }
    
                //使用Expression和EvaluationContext来解析EL表达式
                String cacheKey = prifix + "::" + expression.getValue(evaluationContext).toString();
    
                //判断缓存是否存在
                value = redisTemplate.opsForValue().get(cacheKey);
                if(value != null){
                    logger.info("从缓存中读取到的key:" + cacheKey +",value:" + value);
                    return value;
                }
    
                //不存在则执行数据库方法进行查询
                value = proceedingJoinPoint.proceed();
    
                //将查询到的内容存到Redis
                redisTemplate.opsForValue().set(cacheKey,value);
            }catch (Throwable throwable){
                throwable.printStackTrace();
            }
            //方法执行后返回查询结果
            return value;
        }
    }
    

    编写配置类

    无论是在SpringMvc框架还是Springboot框架中,都可以通过编写配置类的方式来配置需要加载的bean对象,具体的配置类代码如下:

    /**
     * 通过注解的形式来配置spring中的bean
     * 使用自定义注解方式来实现Redis缓存
     * @author young
     */
    @Configuration
    @EnableAspectJAutoProxy //开启AOP自动代理
    public class AppConfig {
    
        /**
         * 通过注释来获取properties配置文件中的自定义值,引号里边为EL表达式
         */
        @Value("${spring.redis.host}")
        String host;
    
        @Value("${spring.redis.port}")
        int port;
    
        /**
         * 通过RedisConnectionFactory来获取RedisTemplate,从而进行Redis的相关操作(注解方式同样需要)
         * @return
         */
        @Bean
        public RedisConnectionFactory redisConnectionFactory(){
            //配置Redis的主机和端口
            RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
            redisStandaloneConfiguration.setHostName(host);
            redisStandaloneConfiguration.setPort(port);
    
            //
            RedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration);
            return redisConnectionFactory;
        }
    
        /**
         * 加载RedisTemplate bean
         * @param redisConnectionFactory
         * @return
         */
        @Bean
        public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
            RedisTemplate redisTemplate = new RedisTemplate();
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            //指定Redis序列化的方式
            redisTemplate.setKeySerializer(StringRedisSerializer.UTF_8);
            return redisTemplate;
        }
    }
    

    这样,一个自定义Redis缓存注解的实现也就基本完成了,这对于我们了解注解的底层原理也是很有帮助的。

  • 相关阅读:
    主题:钩子函数简析及实例
    boa安装
    Inno Setup入门(二十一)——Inno Setup类参考(7)
    Inno Setup入门(二十)——Inno Setup类参考(6)
    Inno Setup入门(十九)——Inno Setup类参考(5)
    Inno Setup入门(十八)——Inno Setup类参考(4)
    Inno Setup入门(十七)——Inno Setup类参考(3)
    Inno Setup入门(十六)——Inno Setup类参考(2)
    sqlite 增加字段语句
    判断 Selite中标存在或者字段存在的方法
  • 原文地址:https://www.cnblogs.com/mr-ziyoung/p/13943508.html
Copyright © 2020-2023  润新知