栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring中如何通过自定义注解加对接口进行加缓存?

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring中如何通过自定义注解加对接口进行加缓存?

spring中如何通过自定义注解加对接口进行加缓存?

近期为了快速升职加薪,不断的学习架构之路
以前在使用Redis缓存时,经常是在代码中通过调用RedisTemplate进行操作缓存的,哪里需要加缓存,就通过这种方式来使用,当时也没多想,觉得用得还挺顺手的,甚至其他同事在使用Redis时,基本上的使用方式和我是一样的,没啥区别

但是最近学习了架构之后,总感觉之前的做法不太好,每次加缓存,都要得去修改代码,增加缓存的代码,而修改代码很容易引起很多风险
为什么有风险?因为至少每次都需要有以下两个步骤
1.先去获取缓存,在判断缓存是否存在,如果已经存在,则直接返回
2.缓存不存在,就去读数据库,将数据写入缓存

这只是一个简单的场景,当然,实际上可能不仅仅这两步,可能还要涉及到读库时要加锁…

总之,一句话,这种方式去加锁,存在比较打的风险

如何避免加缓存带来的风险?

其实,有了架构思想后,就简单很多了,以不变应万变,这也是高级架构师必须具备的思想

怎么以不变应万变?

经过了上述分析,我们知道加缓存必须经过上述说到的至少2个步骤,我们这里就按照两个步骤进行思考架构

既然加缓存,必须要写代码,但是怎么写,才能减少风险?
那就是自定义注解类,在需要加缓存的接口上,加上一个注解,这样在调用接口的过程中,如果缓存没有数据,自动的去查库,然后设置缓存,如果缓存有数据,就直接返回。然后在基于AOP和spring框架,即可实现,代码如下

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CoustomCache {
    
    String key();
}

AOP实现:

@Component
@Aspect
public class CoustomCacheAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(edu.dongnao.study.redis.apply.lesson1.custom.annotations.CoustomCache)")
    public void cachePointcut() {
    }

    // 定义相应的事件
    @Around("cachePointcut()")
    public Object doCache(ProceedingJoinPoint joinPoint) {
        Object value = null;
        try {
            // 0-1、 当前方法上注解的内容
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = joinPoint.getTarget().getClass().getMethod(signature.getName(), signature.getMethod().getParameterTypes());
            CoustomCache cacheAnnotation = method.getAnnotation(CoustomCache.class);
            String keyEl = cacheAnnotation.key();
            // 0-2、 前提条件:拿到作为key的依据  - 解析springEL表达式
            // 创建解析器
            expressionParser parser = new SpelexpressionParser();
            expression expression = parser.parseexpression(keyEl);
            evaluationContext context = new StandardevaluationContext(); // 参数
            // 添加参数
            Object[] args = joinPoint.getArgs();
            DefaultParameterNameDiscoverer discover = new DefaultParameterNameDiscoverer();
            String[] parameterNames = discover.getParameterNames(method);
            for (int i = 0; i < parameterNames.length; i++) {
                context.setVariable(parameterNames[i], args[i].toString());
            }
            // 解析
            String key = expression.getValue(context).toString();

            // 1、 判定缓存中是否存在
            value = redisTemplate.opsForValue().get(key);
            if (value != null) {
                System.out.println("从缓存中读取到值:" + value);
                return value;
            }

            // 2、不存在则执行方法
            value = joinPoint.proceed();

            // 3、 同步存储value到缓存。
            redisTemplate.opsForValue().set(key, value);

        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return value;
    }


}

测试用例:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
@ActiveProfiles("custom") // 设置profile
public class CustomCacheTests {

    @Autowired
    CustomAnnoDemoService customDemoService;

    // get
    @Test
    public void springCacheTest() throws Exception {
        User user = customDemoService.findUserById("wahaha");
        System.out.println(user);
    }
}

这里只是为了说明架构思路和实现自定义注解加缓存的案例,源码就不提供了

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/756590.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号