IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 利用Aop+分布式锁 -> 正文阅读

[Java知识库]利用Aop+分布式锁

模拟:@Transactional 来完成任务!
定义一个注解

?

?

package com.Zh.gmall.common.cache;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author OZH
 * @Description:引出如何利用Aop+分布式锁!
 * 模拟:@Transactional   来完成任务
 * 定义一个自定义注解  GmallCache
 * @date 2022/2/6 19:24
 */
//@Target({ElementType.TYPE, ElementType.METHOD})//当前注解使用的级别,第一个Type表示在类上,第二个表示在方法上
    @Target(ElementType.METHOD)//只在方法上使用
    @Retention(RetentionPolicy.RUNTIME)
public @interface GmallCache {

    //是否需要定义属性:  锁的前缀!
    String prefix() default "cache";//默认是cache,方法名可以改变
}

GmallCachAspect编写

package com.Zh.gmall.common.cache;

import com.Zh.gmall.common.constant.RedisConst;
import com.alibaba.fastjson.JSON;
import lombok.SneakyThrows;
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.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 org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * @author OZH
 * @Description:
 * @date 2022/2/6 21:11
 */
@Component
@Aspect

public class GmallCachAspect {
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RedisTemplate redisTemplate;
    //切注解
    @SneakyThrows//如果有异常的话都能收掉,不加换成try catch
    @Around("@annotation(com.Zh.gmall.common.cache.GmallCache)")
    public Object gmallCacheGetData(ProceedingJoinPoint joinPoint) {

        /**
         * 1.获取方法上的注解
         * 2.获取到注解的前缀,并组成缓存的key
         * 3.根据key 获取缓存中的数据
         * 4.判断是否获取到了数据{分布式锁的业务逻辑}
         */
        Object object = null;
        //因为GmallCache是在方法上的所以使用MethodSignature
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        GmallCache gmallCache = signature.getMethod().getAnnotation(GmallCache.class);//拿到方法上的注解
        //获取到注解的前缀
        String prefix = gmallCache.prefix();
        //获取到方法上的参数
        Object[] args = joinPoint.getArgs();
//        String key = prefix + args.toString();
        // 定义缓存的key
        String key = prefix + Arrays.asList(args);
        try {
            //从缓存获取方法
            object = getCache(key,signature);
            //判断
            if (object == null) {
                //分布式锁的业务逻辑
                //先加锁
                RLock lock = redissonClient.getLock(key + ":lock");
                //上锁:
                boolean flag = lock.tryLock(RedisConst.SKULOCK_EXPIRE_PX1, RedisConst.SKULOCK_EXPIRE_PX2, TimeUnit.SECONDS);
                if (flag) {
                    try {
                        //执行的业务逻辑:查询数据库数据!
                        object = joinPoint.proceed(joinPoint.getArgs());//被GmallCache注解的方法的方法体的代码块
                        // 判断  防止缓存穿透
                        if (object == null) {
                            Object object1 = new Object();
                            redisTemplate.opsForValue().set(key, JSON.toJSONString(object1), RedisConst.SKUKEY_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                            return object1;
                        }
                        //  不为空!skuinfo不为空
                        redisTemplate.opsForValue().set(key, JSON.toJSONString(object), RedisConst.SKUKEY_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
                        //返回数据
                        return object;
                    } finally {
                        lock.unlock();

                    }
                } else {
                    //没有获取到锁对象
                    try {
                        Thread.sleep(300);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    return gmallCacheGetData(joinPoint);
                }
            } else {
                return object;
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        //数据库兜底,直接访问数据库
        Object proceed = joinPoint.proceed(joinPoint.getArgs());
        return proceed;
    }

    /**
     * 获取缓存
     * @param key
     * @return
     */
    private Object getCache(String key,MethodSignature signature) {
        //返回String
        String sObject = (String) redisTemplate.opsForValue().get(key);
        if (!StringUtils.isEmpty(sObject)) {//不为空
            //  返回数据! 获取到返回类型
            //  如果缓存 : public BigDecimal getSkuPrice(Long skuId) 返回值 BigDecimal
            //  如果缓存:  public List<SpuSaleAttr> getSpuSaleAttrListCheckBySku(Long skuId, Long spuId) 返回SpuSaleAttr
            //  如果缓存:  public SkuInfo getSkuInfo(Long skuId) 返回SkuInfo

            //获取到返回值类型
            Class returnType = signature.getReturnType();
        //将字符串变为要返回的数据类型

            return JSON.parseObject(sObject, returnType);
        }
        //为空的话
        return null;
    }

}

有一个小细节,Object没有序列化,从redis获取的时候要知道返回值类型,然后将获取到的Json对象转化为对应类型的对象

?存入的时候要以JSON格式存储

?然后在impl,com/Zh/gmall/product/service/impl/ManageServiceImpl

需要加入缓存的方法上面添加注解

参数为前缀,看到这你应该会记得了?

?运行测试

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-07 13:35:18  更:2022-02-07 13:37:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:49:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码