spring中如何通过自定义注解对接口进行加缓存?架构可以让你不改已存在的代码

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

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

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

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

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

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

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

怎么以不变应万变?

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

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

自定义注解

/**
 * 自定义cache注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CoustomCache {
    /**
     * key的规则,可以使用springEL表达式,可以使用方法执行的一些参数
     */
    String key();
}

AOP实现:

@Component
@Aspect
public class CoustomCacheAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("@annotation(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;
    }


}
package custom;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import custom.annotations.CoustomCache;
import custom.pojo.User;

@Service
@Profile("custom")
public class CustomAnnoDemoService {
   @CoustomCache(key = "#userId")
    public User findUserById(String userId) throws Exception {
        User user = null;
        user = new User(userId, "张三");
        System.out.println("从数据库中读取到值:" + user);
        return user;
    }
}

测试用例:

@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);
    }
}

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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值