基于SpringAOP+Caffeine實現(xiàn)本地緩存的實例,文中有詳細的代碼供大家參考,需要的朋友可以參考下" />

亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

基于SpringAOP+Caffeine實現(xiàn)本地緩存的實例代碼

 更新時間:2024年03月22日 09:01:36   作者:花自飄0水自流  
公司想對一些不經(jīng)常變動的數(shù)據(jù)做一些本地緩存,我們使用AOP+Caffeine來實現(xiàn),所以本文給大家介紹了
基于SpringAOP+Caffeine實現(xiàn)本地緩存的實例,文中有詳細的代碼供大家參考,需要的朋友可以參考下

一、背景

公司想對一些不經(jīng)常變動的數(shù)據(jù)做一些本地緩存,我們使用AOP+Caffeine來實現(xiàn)

二、實現(xiàn)

1、定義注解

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

/**
 * 本地緩存
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LocalCacheable {

    // 過期時間 默認(rèn)10分鐘
    long expired() default 600;

    // key創(chuàng)建器
    String keyGenerator() default "org.springframework.cache.interceptor.KeyGenerator";
}

2、切面

import com.google.gson.internal.LinkedTreeMap;
import org.apache.commons.lang3.ArrayUtils;
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.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 本地緩存
 */
@Aspect
@Component
public class LocalCacheAspect {

    private static final String separator = ":";

    @Around("@annotation(com.framework.localcache.LocalCacheable)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        if (AopUtils.isAopProxy(point.getTarget())) {
            return point.proceed();
        }

        Method method = getMethodSignature(point).getMethod();
        if (method == null) {
            return point.proceed();
        }

        LocalCacheable annotation = method.getAnnotation(LocalCacheable.class);
        if (annotation == null) {
            return point.proceed();
        }

        // 生成key
        String key = generateKey(point);
//         System.out.println("生成的key:" + key);

        long expired = annotation.expired();

        Throwable[] throwable = new Throwable[1];
        Object proceed = LocalCache.cacheData(key, () -> {
            try {
                return point.proceed();
            } catch (Throwable e) {
                throwable[0] = e;
            }
            return null;
        }, expired);

        if (throwable[0] != null) {
            throw throwable[0];
        }

        return proceed;
    }

    /**
     * 獲取方法
     */
    private MethodSignature getMethodSignature(ProceedingJoinPoint point) {
        Signature signature = point.getSignature();
        if (signature instanceof MethodSignature) {
            return ((MethodSignature) signature);
        }
        return null;
    }

    /**
     * 獲取key
     */
    private String generateKey(ProceedingJoinPoint point) {

        // 目標(biāo)類、方法、參數(shù)等
        Class<?> targetClass = AopProxyUtils.ultimateTargetClass(point.getTarget());
        Method method = getMethodSignature(point).getMethod();
        String[] parameterNames = getMethodSignature(point).getParameterNames();
        Object[] args = point.getArgs();

        // 解析參數(shù),生成key
        LinkedTreeMap<String, Object> paramResolveResult = new LinkedTreeMap<>();
        if (ArrayUtils.isNotEmpty(args)) {
            for (int i = 0; i < args.length; i++) {
                resolveParam(args[i], paramResolveResult, parameterNames[i]);
            }
        }

        StringBuilder key = new StringBuilder(targetClass.getName() + separator + method.getName() + separator);
        paramResolveResult.forEach((k, v) -> {
            if (v != null) {
                key.append(k + "," + v + separator);
            }
        });

        // 根據(jù)方法名和參數(shù)生成唯一標(biāo)識
        return key.toString();
    }


    private void resolveParam(Object param, Map<String, Object> paramResolveResult, String prefix) {
        if (param == null) {
            return;
        }
        Class<?> type = param.getClass();
        if (type == List.class) {
            List<Object> param0 = (List) param;
            for (int i = 0; i < param0.size(); i++) {
                resolveParam(param0.get(i), paramResolveResult, prefix + "[" + i + "]");
            }
        } else if (type == Map.class) {
            Map<Object, Object> param0 = (Map) param;
            param0.forEach((k, v) -> {
                resolveParam(v, paramResolveResult, prefix + "." + k);
            });
        } else if (type.isArray()) {
            Object[] param0 = (Object[]) param;
            for (int i = 0; i < param0.length; i++) {
                resolveParam(param0[i], paramResolveResult, prefix + "[" + i + "]");
            }
        } else if (type == Byte.class
                || type == Short.class
                || type == Integer.class
                || type == Long.class
                || type == Float.class
                || type == Double.class
                || type == Boolean.class
                || type == Character.class
                || type == String.class) {
            paramResolveResult.put(prefix, param);
        } else {
            // 復(fù)雜類型
            Map<String, Object> fieldMap = new HashMap<>();
            // CGLIB代理
            if (Enhancer.isEnhanced(type)) {
                getAllFieldsAndValue(param, type.getSuperclass(), fieldMap);
            } else {
                getAllFieldsAndValue(param, type, fieldMap);
            }

            fieldMap.forEach((k, v) -> {
                if (v == null) {
                    return;
                }
                resolveParam(v, paramResolveResult, prefix + "." + k);
            });
        }
    }

    /**
     * 獲取所有字段和值
     */
    private void getAllFieldsAndValue(Object o, Class type, Map<String, Object> fieldMap) {

        for (Field field : type.getDeclaredFields()) {
            if (field.trySetAccessible()) {
                try {
                    fieldMap.put(field.getName(), field.get(o));
                } catch (IllegalAccessException e) {}
            }
        }

        if (type.getSuperclass() != Object.class) {
            getAllFieldsAndValue(o, type.getSuperclass(), fieldMap);
        }
    }


}

3、緩存工具類

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

/**
 * 本地緩存
 */
public class LocalCache {

    private static final Map<Long, Cache<Object, Object>> cacheMap = new ConcurrentHashMap<>();

    /**
     * 創(chuàng)建本地緩存
     * @param seconds 過期時間:秒
     */
    private static Cache<Object, Object> createCache(long seconds) {
        return Caffeine.newBuilder()
                .expireAfterWrite(seconds, TimeUnit.SECONDS)
                .build();
    }

    /**
     * 創(chuàng)建本地緩存
     * @param seconds 過期時間:秒
     * @param loader 緩存方法
     */
    private Cache<Object, Object> createLoadingCache(long seconds, CacheLoader<Object, Object> loader) {
        return Caffeine.newBuilder()
                .expireAfterWrite(seconds, TimeUnit.SECONDS)
                .build(loader);
    }


    /**
     * 獲取一個緩存組
     * @param seconds 緩存過期時間
     */
    private static Cache<Object, Object> getAndLoad(long seconds) {
        if (cacheMap.containsKey(seconds)) {
            return cacheMap.get(seconds);
        }

        Cache<Object, Object> cache = createCache(seconds);
        cacheMap.put(seconds, cache);

        return cache;
    }

    /**
     * 緩存數(shù)據(jù),過期時間默認(rèn)10分鐘
     * @param key key
     * @param supplier 數(shù)據(jù)來源的方法
     */
    public static Object cacheData(Object key, Supplier<Object> supplier) {
        return cacheData(key, supplier, 600);
    }


    /**
     * 緩存數(shù)據(jù)
     * @param key key
     * @param supplier 數(shù)據(jù)來源的方法
     * @param seconds 過期時間:秒
     */
    public static Object cacheData(Object key, Supplier<Object> supplier, long seconds) {
        Assert.state(seconds > 0, "過期時間必須大于0秒");
        Cache<Object, Object> cache = getAndLoad(seconds);
        return cache.get(key, k -> supplier.get());
    }
}

三、測試

    @LocalCacheable
    @GetMapping("test1")
    public String test1() {
        System.out.println("執(zhí)行了");
        return "success";
    }

    @LocalCacheable
    @GetMapping("test2")
    public String test2(String a) {
        System.out.println("執(zhí)行了" + a);
        return "success";
    }

    @LocalCacheable
    @GetMapping("test3")
    public String test3(String a, int b, String c) {
        System.out.println("執(zhí)行了" + a + b + c);
        return "success";
    }

    @LocalCacheable
    @GetMapping("test4")
    public String test4(UserInfo user) {
        System.out.println("執(zhí)行了" + user);
        return "success";
    }


    @LocalCacheable
    @GetMapping("test5")
    public String test5(UserInfo[] users) {
        System.out.println("執(zhí)行了" + users);
        return "success";
    }


    @LocalCacheable
    @GetMapping("test6")
    public String test6(List<UserInfo> users) {
        System.out.println("執(zhí)行了" + users);
        return "success";
    }


    @LocalCacheable
    @GetMapping("test7")
    public String test7(UserInfo user) {
        System.out.println("執(zhí)行了" + user.getMap());
        return "success";
    }

到此這篇關(guān)于基于SpringAOP+Caffeine實現(xiàn)本地緩存的文章就介紹到這了,更多相關(guān)SpringAOP affeine本地緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java中斷機制實例講解

    java中斷機制實例講解

    這篇文章主要介紹了java中斷機制實例講解,用了風(fēng)趣幽默的講法,有對這方面不太懂的同學(xué)可以研究下
    2021-01-01
  • spring boot整合Swagger2的示例代碼

    spring boot整合Swagger2的示例代碼

    Swagger 是一個規(guī)范和完整的框架,用于生成、描述、調(diào)用和可視化RESTful風(fēng)格的 Web 服務(wù)。這篇文章主要介紹了spring boot整合Swagger2,需要的朋友可以參考下
    2017-04-04
  • 深入探究Bean生命周期的擴展點Bean Post Processor

    深入探究Bean生命周期的擴展點Bean Post Processor

    在Spring框架中,Bean生命周期的管理是非常重要的一部分,在Bean的創(chuàng)建、初始化和銷毀過程中,Spring提供了一系列的擴展點,其中,Bean Post Processor(后處理器)是一個重要的擴展點,它能夠在Bean的初始化前后做一些額外的處理,本文就和大家一起深入探究
    2023-07-07
  • IDEA啟動Springboot報錯:無效的目標(biāo)發(fā)行版:17 的解決辦法

    IDEA啟動Springboot報錯:無效的目標(biāo)發(fā)行版:17 的解決辦法

    這篇文章主要給大家介紹了IDEA啟動Springboot報錯:無效的目標(biāo)發(fā)行版:17 的解決辦法,文中通過代碼示例和圖文講解的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-02-02
  • Java日常練習(xí)題,每天進步一點點(58)

    Java日常練習(xí)題,每天進步一點點(58)

    下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,希望可以幫到你
    2021-08-08
  • SpringBoot中攔截器和動態(tài)代理的區(qū)別詳解

    SpringBoot中攔截器和動態(tài)代理的區(qū)別詳解

    在?Spring?Boot?中,攔截器和動態(tài)代理都是用來實現(xiàn)功能增強的,所以在很多時候,有人會認(rèn)為攔截器的底層是通過動態(tài)代理實現(xiàn)的,所以本文就來盤點一下他們兩的區(qū)別,以及攔截器的底層實現(xiàn)吧
    2023-09-09
  • java 漢諾塔Hanoi遞歸、非遞歸(仿系統(tǒng)遞歸)和非遞歸規(guī)律 實現(xiàn)代碼

    java 漢諾塔Hanoi遞歸、非遞歸(仿系統(tǒng)遞歸)和非遞歸規(guī)律 實現(xiàn)代碼

    漢諾塔(Hanoi) 算法Java實現(xiàn)。通過三個函數(shù),分別對Hanoi進行遞歸、非遞歸和非遞歸規(guī)律實現(xiàn)。
    2013-05-05
  • spring?IOC容器的Bean管理XML自動裝配過程

    spring?IOC容器的Bean管理XML自動裝配過程

    這篇文章主要為大家介紹了spring?IOC容器Bean管理基于XML的自動裝配過程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • kotlin和Java的相互調(diào)用示例詳解

    kotlin和Java的相互調(diào)用示例詳解

    Kotlin 的設(shè)計過程中就考慮到了與 Java 的互操作性。在 Kotlin 中可以直接調(diào)用既有的 Java 代碼, 反過來在 Java 中也可以很流暢地使用 Kotlin 代碼,下面這篇文章主要給大家介紹了關(guān)于kotlin和Java的相互調(diào)用的相關(guān)資料,需要的朋友可以參考下。
    2018-02-02
  • Spring?Boot項目Jar包加密實戰(zhàn)教程

    Spring?Boot項目Jar包加密實戰(zhàn)教程

    本文詳細介紹了如何在Spring?Boot項目中實現(xiàn)Jar包加密,我們首先了解了Jar包加密的基本概念和作用,然后學(xué)習(xí)了如何使用Spring?Boot的Jar工具和第三方庫來實現(xiàn)Jar包的加密和解密,感興趣的朋友一起看看吧
    2024-02-02

最新評論