AOP切面编程+布隆过滤器+加锁 最终版

AOP切面编程+布隆过滤器+加锁 最终版
因为布隆过滤器是村商品的id信息,所以其他的业务不一定用得到,所以注解里面自定义一个boolean值来决定是否开启布隆过滤器,且把非核心业务代码抽到一个切面类中

package com.atguigu.aop;

import com.atguigu.constant.RedisConst;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName ShopCacheAspect
 * @Author dx
 * @Date 2023/7/17 13:43
 */
@Component
@Aspect
public class ShopCacheAspect {


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RBloomFilter rBloomFilter;

    @Around("@annotation(com.atguigu.aop.ShopCache)")
    public Object cacheAroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        //1.获取到目标方法上面的参数的第一个
        Object[] prams = joinPoint.getArgs();
        Object firstParam = prams[0];
        //获取目标方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method signatureMethod = methodSignature.getMethod();
        //拿到目标方法上面的注解
        ShopCache shopCache = signatureMethod.getAnnotation(ShopCache.class);
        String prefix = shopCache.value();
        String cacheKey=prefix+":"+firstParam;
        //减小锁的粒度
        String lockKey="lock-"+firstParam;
        //因为是查询的操作,不改变数据库不是增删改 所以可以使用本地锁
        Object objectCache =  redisTemplate.opsForValue().get(cacheKey);
        if (objectCache==null){
            //保证拿到的锁是同一个
            synchronized (lockKey.intern()){
                if (objectCache == null) {
                    //是否开启布隆过滤器
                    boolean bloom = shopCache.bloom();
                    Object FromDb=null;
                    if (bloom){//为true 开启布隆过滤器
                        boolean flag = rBloomFilter.contains(firstParam);
                        if (flag){
                             FromDb = joinPoint.proceed();
                            //把数据放入redis
                            redisTemplate.opsForValue().set(cacheKey, FromDb, RedisConst.SKUKEY_TIMEOUT, TimeUnit.SECONDS);
                            return FromDb;
                        }
                    }else {
                         FromDb = joinPoint.proceed();
                        //把数据放入redis
                        redisTemplate.opsForValue().set(cacheKey, FromDb, RedisConst.SKUKEY_TIMEOUT, TimeUnit.SECONDS);
                        return FromDb;
                    }

                }
            }

        }

        return objectCache;
    }
}

自定义注解

package com.atguigu.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//运行时使用
@Retention(RetentionPolicy.RUNTIME)
//在方法和类上可用使用该注解
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface ShopCache {
    //定义属性值
    String value() default "cache";
    //定义一个布尔类型值
    boolean bloom() default  true;
}

业务代码


    //根据skuId查询商品的基本信息 先走redis 没有再走数据库
    //走redis的代码抽取到一个切面类中(AOP的思想)  @ShopCache设置了属性value 为了区分不同的方法的不同的缓存key
    @ShopCache(value = "skuInfo")
    @Override
    public SkuInfo getSkuInfo(Long skuId) {
        SkuInfo skuInfo = getSkuInfoFromDb(skuId);
        return skuInfo;
    }


   /**
     * 数据库查询
     * @param skuId
     * @return
     */
    private SkuInfo getSkuInfoFromDb(Long skuId) {
        SkuInfo skuInfo = this.getById(skuId);
        if (skuInfo!=null){
            LambdaQueryWrapper<SkuImage> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SkuImage::getSkuId, skuId);
            List<SkuImage> imageList = skuImageService.list(wrapper);
            skuInfo.setSkuImageList(imageList);
        }
        return skuInfo;
    }

如果value值设置的为 @ShopCache(value = “skuInfo:#{#params}”)
则需要El表达式来解析然后拿到拼接拿到key 当然这是少数情况

  public String getExpressionValue(String key,Object[] methodParams){
        //a.获取一个spring表达式解析器
        SpelExpressionParser elParser = new SpelExpressionParser();
        //b.利用解析器解析表达式
        Expression expression = elParser.parseExpression(key, new TemplateParserContext());
        //c.准备一个计算环境
        StandardEvaluationContext context = new StandardEvaluationContext();
        //d.设置表达式的值
        context.setVariable("params",methodParams);
        //e.表达式解析之后结果
        String retVal = expression.getValue(context, String.class);
        return retVal;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring AOP切面编程是一种通过配置的方式,实现在Spring开发中的AOP功能。切面由切点和增强组成,切点用于定义在哪些连接点上应用增强,而增强指的是在连接点上要执行的逻辑操作。Spring的AOP强大之处在于不需要通过代码,只需要使用注解或XML配置就可以完成相同的功能。 在学习Spring开发的AOP面向切面编程时,需要导入相应的jar包,例如com.springsource.net.sf.cglib-2.2.0.jar com.springsource.org.aopalliance-1.0.0.jar com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar。切面编程是一种实现横切关注点的重用和集中管理的技术,它可以让我们更加方便地实现一些横切关注点,如日志记录、事务管理等,并将其与业务逻辑分离开来,提高代码的复用性和可维护性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [spring AOP切面编程](https://blog.csdn.net/weixin_43525993/article/details/107902045)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [SpringAOP切面编程依赖jar包.rar](https://download.csdn.net/download/weixin_44888416/12374630)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值