惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
O
OpenAI News
V
V2EX
大猫的无限游戏
大猫的无限游戏
博客园 - 聂微东
S
Schneier on Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
小众软件
小众软件
L
LINUX DO - 热门话题
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - Franky
Security Latest
Security Latest
S
SegmentFault 最新的问题
Project Zero
Project Zero
Spread Privacy
Spread Privacy
K
Kaspersky official blog
J
Java Code Geeks
V
Vulnerabilities – Threatpost
C
Cisco Blogs
C
CERT Recently Published Vulnerability Notes
月光博客
月光博客
T
The Exploit Database - CXSecurity.com
L
Lohrmann on Cybersecurity
人人都是产品经理
人人都是产品经理
博客园 - 三生石上(FineUI控件)
Scott Helme
Scott Helme
WordPress大学
WordPress大学
量子位
T
Threat Research - Cisco Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
宝玉的分享
宝玉的分享
Hugging Face - Blog
Hugging Face - Blog
AWS News Blog
AWS News Blog
Help Net Security
Help Net Security
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Simon Willison's Weblog
Simon Willison's Weblog
S
Secure Thoughts
博客园 - 【当耐特】
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
V
Visual Studio Blog
Last Week in AI
Last Week in AI
T
Tailwind CSS Blog
腾讯CDC
Cyberwarzone
Cyberwarzone
IT之家
IT之家
GbyAI
GbyAI
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
云风的 BLOG
云风的 BLOG
T
Troy Hunt's Blog
D
Docker

博客园 - 陈惟鲜的博客

win11安装mysql8 AI软件修改脚本与代码,还真不敢完全操作 linux 磁盘满了,排查 Ecelipse 安装 MAT linux 增加新磁盘 redis自身查询很慢 排查redis-benchmark prometheus监控mysql数据库 prometheus监控springboot项目配置 监控工具prometheus配置-docker版 linux 文件属性被替换修改查询并修改 ----i----------- ZonedDateTime 转为 java.util.Date docker 容器查看jvm参数配置 redis 事务处理,一旦异常,则回滚 linux 下安装使用jmeter 执行压测 大批量订单来了由于入库慢,先缓存后通知入库 eclipse 合并错分支代码还原,合并到本分支但未push到库上 mysql 查询jason格式数据 maven打包慢,使用maven-mvnd 打包可以快一半 postman 参数化构建 批量测试 postman 常用参数例子 如何判断redis慢了
使用AOP实现+自定义注解 实现 缓存
陈惟鲜的博客 · 2023-05-17 · via 博客园 - 陈惟鲜的博客

一般做一个缓存处理,我们正常的做法是在需要缓存的方法中。

查询缓存是否存在,不存在,查询(DB或远程接口),如果数据存在,那么则缓存,否则下次记录查询。

当我们做1、2、3个方法这样写还行,如果有10、20个方法需要缓存,这样是不是就很繁琐了。。

所以,我们需要一个标签来做缓存,当然springcache提供有缓存的标签。还有各种策略。

但是,我就是要自己写一个。。

这个处理的方式原理就是通过AOP拦截自己定义的标签,然后通过标签中的参数,决定缓存多久,加标签的就做缓存。

单独几个的写法如下:

    @Autowired
    private RedisTemplate redisTemplate;
    /**查询数据*/
    public Object selectValue(String dicCode, String key) {
        String redisKey = "selectValue"+dicCode+key;
        Object result = redisTemplate.opsForValue().get(redisKey);
        if (null == result) {
            result = dictionaryDao.getDicInfoValue(dicCode, key);
            if (null != result) {
                redisTemplate.opsForValue().set(redisKey, result, 30, TimeUnit.SECONDS);
            }
        }
        return result;
    }

当我们做了几个后,修改成AOP+自定义注解

自定义注解:RedisCacheAT.java

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

/**
 * @desc:缓存注解-redis
 * @author 陈惟鲜
 * @date 2023年5月10日 下午7:36:28
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RedisCacheAT {
    
    /**缓存时间,默认60秒*/
    public int times() default 60;
}

AOP切面:

RedisCacheAOP.java

import java.util.concurrent.TimeUnit;

import javax.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.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;/**
 * @Desc : 本地缓存方法,方法上加上@LocalCache即可
 * @Company : 晨创科技
 * @author : Chenweixian 陈惟鲜
 * @Date : 2021年5月7日 下午7:47:56
 */
@SuppressWarnings({"rawtypes","unchecked"})
@Aspect
@Component
@Order(8) // @Order(1)数字越小优先级越高
public class RedisCacheAspect {
    
    @Resource
    private RedisTemplate redisTemplate;
    
    /**拦截所有controller包下的方法*/
    @Pointcut("@annotation(com.ccjr.core.logcollection.annotation.RedisCacheAT)")
    private void myMethod(){
    }
    
    /** 
     *  日志打印
     * @author : 陈惟鲜 chenweixian
     * @Date : 2022年8月8日 下午5:29:47
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("myMethod() && @annotation(cache)")  
    public Object doAround(ProceedingJoinPoint point, RedisCacheAT cache) throws Throwable {
        String class_name = point.getTarget().getClass().getName();
        String method_name = point.getSignature().getName();
        String requestStr = MyAopUtils.getRequestParam(point);
        String cacheKey = class_name + "." + method_name + requestStr;
     // 防止key过长,直接取md5值 cacheKey
= "redisCache:"+MD5Utils.getMD5(cacheKey); Object result = redisTemplate.opsForValue().get(cacheKey); if (null == result) { result = point.proceed();// result的值就是被拦截方法的返回值 if (null != result) { redisTemplate.opsForValue().set(cacheKey, result, cache.times(), TimeUnit.SECONDS); } } return result; } }

其中工具类获取请求参数

import org.apache.commons.lang.ArrayUtils;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 *  切面拦截工具
 * @Company : 晨创科技
 * @author : Chenweixian
 * @Date : 2022年11月15日 下午10:45:01
 */
public class MyAopUtils {
    /**
     *  参数处理,超过指定长度字符的,只显示1000...
     * @author : 陈惟鲜 chenweixian
     * @Date : 2018年8月10日 上午11:44:11
     * @param paramStr
     * @param strlength
     * @return
     */
    public static String parameterHandle(String paramStr, int strlength){
        if (paramStr.length() > strlength){
            paramStr = paramStr.substring(0, strlength) + "...";
        }
        if (paramStr.length() > 10){
            paramStr = "[" + paramStr + "]";
        }
        return paramStr;
    }
    
    /***
     *  获取请求参数
     * @author : 陈惟鲜 chenweixian
     * @Date : 2018年8月9日 下午3:47:08
     * @param point
     * @return
     */
    public static String getRequestParam(ProceedingJoinPoint point){
        /**
         * 获取方法的参数值数组。
         */
        Object[] methodArgs = point.getArgs();
        
        // 结果
        String requestStr = "";
        /**
         * 获取方法参数名称
         */
         try {
            requestStr = logParam(methodArgs);
        } catch (Exception e) {
            requestStr = "获取参数失败";
        }
        return requestStr;
    }
    
//    /**
//     * 使用javassist来获取方法参数名称
//     * @param class_name    类名
//     * @param method_name   方法名
//     * @return
//     * @throws Exception
//     */
//    private String[] getFieldsName(String class_name, String method_name) throws Exception {
//        Class<?> clazz = Class.forName(class_name);
//        String clazz_name = clazz.getName();
//        ClassPool pool = ClassPool.getDefault();
//        ClassClassPath classPath = new ClassClassPath(clazz);
//        pool.insertClassPath(classPath);
//
//        CtClass ctClass = pool.get(clazz_name);
//        CtMethod ctMethod = ctClass.getDeclaredMethod(method_name);
//        MethodInfo methodInfo = ctMethod.getMethodInfo();
//        CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
//        LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
//        if(attr == null){
//            return null;
//        }
//        String[] paramsArgsName = new String[ctMethod.getParameterTypes().length];
//        int pos = Modifier.isStatic(ctMethod.getModifiers()) ? 0 : 1;
//        for (int i=0;i<paramsArgsName.length;i++){
//            paramsArgsName[i] = attr.variableName(i + pos);
//        }
//        return paramsArgsName;
//    }
    
    /**
     * 判断是否为基本类型:包括String
     * @param clazz clazz
     * @return  true:是;     false:不是
     */
    private static boolean isPrimite(Class<?> clazz){
        if (clazz.isPrimitive() || clazz == String.class){
            return true;
        }else {
            return false;
        }
    }


    /**
     * 打印方法参数值  基本类型直接打印,非基本类型需要重写toString方法
     * @param paramsArgsName    方法参数名数组
     * @param paramsArgsValue   方法参数值数组
     */
    private static String logParam(Object[] paramsArgsValue){
        if(ArrayUtils.isEmpty(paramsArgsValue)){
            return "";
        }
        StringBuffer buffer = new StringBuffer();
        for (int i=0;i<paramsArgsValue.length;i++){
            //参数名
//            String name = paramsArgsName[i];
            //参数值
            Object value = paramsArgsValue[i];
//            buffer.append(name +" = ");
            if(isPrimite(value.getClass())){
                buffer.append(value + "  ,");
            }else {
                buffer.append(value.toString() + "  ,");
            }
        }
        return buffer.toString();
    }
}

修改后,原来的方法,自定义标签使用后,就很简单了。

    /**查询数据*/
    @RedisCacheAT
    public Object selectValue(String dicCode, String key) {
        Object result = dictionaryDao.getDicInfoValue(dicCode, key);
        return result;
    }

完。。。。。。。。。。。。。