当前位置: 代码网 > it编程>数据库>Redis > 如何打造redis缓存组件

如何打造redis缓存组件

2024年12月11日 Redis 我要评论
打造redis缓存组件使用热插拔aop+反射+redis自定义注解+spring el表达式打造redis缓存组件,优雅重构缓存代码redis配置import org.springframework.

打造redis缓存组件

使用热插拔aop+反射+redis自定义注解+spring el表达式打造redis缓存组件,优雅重构缓存代码

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自动代理
public class redisconfig
{
    /**
     * @param lettuceconnectionfactory
     * @return
     *
     * redis序列化的工具配置类,下面这个请一定开启配置
     * 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);
        //设置key序列化方式string
        redistemplate.setkeyserializer(new stringredisserializer());
        //设置value的序列化方式json
        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自动代理
{
    //约等于键的前缀prefix,
    string keyprefix();

    //springel表达式,解析占位符对应的匹配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;

    //配置织入点
    @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 确定方法名后获得该方法上面配置的注解标签myrediscache
            myrediscache myrediscacheannotation = method.getannotation(myrediscache.class);

            //3 拿到了myrediscache这个注解标签,获得该注解上面配置的参数进行封装和调用
            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 获得方法里面的形参个数
            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)
            {
                system.out.println("------redis里面有,我直接返回结果不再打扰mysql: " + result);
                return result;
            }

            //8 redis里面没有,去找msyql查询或叫进行后续业务逻辑
            //-------aop精华部分,才去找finduserbyid方法干活
            //usermapper.selectbyprimarykey(id);
            result = joinpoint.proceed();//主业务逻辑查询mysql,放行放行放行

            //9 mysql步骤结束,还需要把结果存入redis一次,缓存补偿
            if (result != null)
            {
                system.out.println("------redis里面无,还需要把结果存入redis一次,缓存补偿: " + result);
                redistemplate.opsforvalue().set(key, result);
            }
        } catch (throwable throwable) {
            throwable.printstacktrace();
        }

        return result;
    }
}

测试

    /**
     * 会将返回值存进redis里,key生成规则需要程序员用spel表达式自己指定,value就是程序从mysql查出并返回的user
     * redis的key 等于  keyprefix:matchvalue
     */
    @override
    @myrediscache(keyprefix = "user",matchvalue = "#id")
    public user getuserbyid(integer id)
    {
        return usermapper.selectbyprimarykey(id);
    }

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com