日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

springboot使用j2cache框架和aspectj自定义缓存

發(fā)布時(shí)間:2024/9/30 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot使用j2cache框架和aspectj自定义缓存 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 依賴(lài)和工具介紹
  • 項(xiàng)目代碼
    • spring上下文工具類(lèi):
    • 自定義緩存注解
    • 緩存生成鍵工具類(lèi)
    • 自定義緩存攔截器
    • 緩存處理器
    • 緩存結(jié)果和緩存信息實(shí)體封裝
    • 開(kāi)啟聲明式注解
    • controller層使用緩存
  • 總結(jié)

依賴(lài)和工具介紹

<dependency><groupId> org.aspectj</groupId ><artifactId> aspectjweaver</artifactId ><version> 1.8.7</version ></dependency><dependency><groupId>net.oschina.j2cache</groupId><artifactId>j2cache-core</artifactId><version>2.8.0-release</version></dependency>

配置:

j2cache:cache-clean-mode: passiveallow-null-values: trueredis-client: lettuce #指定redis客戶(hù)端使用lettuce,也可以使用Jedisl2-cache-open: true #開(kāi)啟二級(jí)緩存broadcast: net.oschina.j2cache.cache.support.redis.SpringRedisPubSubPolicy# broadcast: jgroupsL1: #指定一級(jí)緩存提供者為caffeineprovider_class: caffeineL2: #指定二級(jí)緩存提供者為redisprovider_class: net.oschina.j2cache.cache.support.redis.SpringRedisProviderconfig_section: lettucesync_ttl_to_redis: truedefault_cache_null_object: falseserialization: fst #序列化方式:fst、kyro、Java caffeine:properties: /caffeine.properties # 這個(gè)配置文件需要放在項(xiàng)目中 lettuce:mode: singlenamespace:storage: genericchannel: j2cachescheme: redishosts: ${pinda.redis.ip}:${pinda.redis.port}password: ${pinda.redis.password}database: ${pinda.redis.database}sentinelMasterId:maxTotal: 100maxIdle: 10minIdle: 10timeout: 10000

caffeine.properties

default=2000, 2h rx=2000, 2h addressBook=2000, 2h

j2cache是OSChina目前正在使用的兩級(jí)緩存框架。

j2cache的兩級(jí)緩存結(jié)構(gòu):

L1: 進(jìn)程內(nèi)緩存 caffeine/ehcache
L2: 集中式緩存 Redis/Memcached
j2cache其實(shí)并不是在重復(fù)造輪子,而是作資源整合,即將Ehcache、Caffeine、redis、Spring Cache等進(jìn)行整合。

由于大量的緩存讀取會(huì)導(dǎo)致L2的網(wǎng)絡(luò)成為整個(gè)系統(tǒng)的瓶頸,因此L1的目標(biāo)是降低對(duì)L2的讀取次數(shù)。該緩存框架主要用于集群環(huán)境中。單機(jī)也可使用,用于避免應(yīng)用重啟導(dǎo)致的ehcache緩存數(shù)據(jù)丟失。

j2cache從1.3.0版本開(kāi)始支持JGroups和Redis Pub/Sub兩種方式進(jìn)行緩存事件的通知。

數(shù)據(jù)讀取順序 -> L1 -> L2 -> DB

關(guān)于j2cache的region概念:
J2Cache 的 Region 來(lái)源于 Ehcache 的 Region 概念。

一般我們?cè)谑褂孟?Redis、Caffeine、Guava Cache 時(shí)都沒(méi)有 Region 這樣的概念,特別是 Redis 是一個(gè)大哈希表,更沒(méi)有這個(gè)概念。

在實(shí)際的緩存場(chǎng)景中,不同的數(shù)據(jù)會(huì)有不同的 TTL 策略,例如有些緩存數(shù)據(jù)可以永不失效,而有些緩存我們希望是 30 分鐘的有效期,有些是 60 分鐘等不同的失效時(shí)間策略。在 Redis 我們可以針對(duì)不同的 key 設(shè)置不同的 TTL 時(shí)間。但是一般的 Java 內(nèi)存緩存框架(如 Ehcache、Caffeine、Guava Cache 等),它沒(méi)法為每一個(gè) key 設(shè)置不同 TTL,因?yàn)檫@樣管理起來(lái)會(huì)非常復(fù)雜,而且會(huì)檢查緩存數(shù)據(jù)是否失效時(shí)性能極差。所以一般內(nèi)存緩存框架會(huì)把一組相同 TTL 策略的緩存數(shù)據(jù)放在一起進(jìn)行管理。
像 Caffeine 和 Guava Cache 在存放緩存數(shù)據(jù)時(shí)需要先構(gòu)建一個(gè) Cache 實(shí)例,設(shè)定好緩存的時(shí)間策略,如下代碼所示:

Caffeine<Object, Object> caffeine = Caffeine.newBuilder();
caffeine = caffeine.maximumSize(size).expireAfterWrite(expire, TimeUnit.SECONDS);
Cache<String, Object> theCache = caffeine.build()
這時(shí)候你才可以往 theCache 寫(xiě)入緩存數(shù)據(jù),而不能再單獨(dú)針對(duì)某一個(gè) key 設(shè)定不同的 TTL 時(shí)間。

而 Redis 可以讓你非常隨意的給不同的 key 設(shè)置不同的 TTL。

J2Cache 是內(nèi)存緩存和 Redis 這類(lèi)集中式緩存的一個(gè)橋梁,因此它只能是兼容兩者的特性。
J2Cache 默認(rèn)使用 Caffeine 作為一級(jí)緩存,其配置文件位于 caffeine.properties 中。一個(gè)基本使用場(chǎng)景如下:

#########################################

# Caffeine configuration # [name] = size, xxxx[s|m|h|d]

#########################################

default = 1000, 30m
users = 2000, 10m
blogs = 5000, 1h
上面的配置定義了三個(gè)緩存 Region ,分別是:

默認(rèn)緩存,大小是 1000 個(gè)對(duì)象,TTL 是 30 分鐘
users 緩存,大小是 2000 個(gè)對(duì)象,TTL 是 10 分鐘
blogs 緩存,大小是 5000 個(gè)對(duì)象,TTL 是 1 個(gè)小時(shí)
例如我們可以用 users 來(lái)存放用戶(hù)對(duì)象的緩存,用 blogs 來(lái)存放博客對(duì)象緩存,兩種的 TTL 是不同的。

項(xiàng)目代碼

現(xiàn)在上代碼,Springbootzhenghej2cache進(jìn)行緩存:

spring上下文工具類(lèi):

/*** Spring上下文工具類(lèi)*/ @Primary @Component public class SpringApplicationContextUtils {private static ApplicationContext springContext;@Autowiredprivate ApplicationContext applicationContext;@PostConstructprivate void init() {springContext = applicationContext;}/*** 獲取當(dāng)前ApplicationContext** @return ApplicationContext*/public static ApplicationContext getApplicationContext() {return springContext;}}

自定義緩存注解

如果項(xiàng)目中很多模塊都需要使用緩存功能,這些模塊都需要調(diào)用j2cache的API來(lái)進(jìn)行緩存操作,這種j2cache提供的原生API使用起來(lái)就比較繁瑣了,并且操作緩存的代碼和我們的業(yè)務(wù)代碼混合到一起,即j2cache的API對(duì)我們的業(yè)務(wù)代碼具有侵入性。那么我們?nèi)绾胃雍?jiǎn)潔、優(yōu)雅的使用j2cache提供的緩存功能呢?

答案就是使用聲明式緩存。所謂聲明式緩存,就是定義緩存注解,在需要使用緩存功能的方法上加入緩存注解即可自動(dòng)進(jìn)行緩存操作。

這種使用方式類(lèi)似于我們以前使用的聲明式事務(wù),即在類(lèi)的方法上加入事務(wù)注解就可以實(shí)現(xiàn)事務(wù)控制。

注意:j2cache原生API和我們實(shí)現(xiàn)的聲明式緩存可以兼容,即在項(xiàng)目中可以同時(shí)使用,互為補(bǔ)充。例如在Controller的方法中需要將多類(lèi)業(yè)務(wù)數(shù)據(jù)載入緩存,此時(shí)通過(guò)聲明式緩存就無(wú)法做到(因?yàn)槁暶魇骄彺嬷荒軐⒎椒ǖ姆祷刂递d入緩存),這種場(chǎng)景下就需要調(diào)用j2cache的原生API來(lái)完成。

/*** 緩存注解*/ @Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Cache {String region() default "rx";String key() default "";String params() default ""; } /*** 清理緩存注解*/ @Documented @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface CacheEvictor {Cache[] value() default {}; }

自定義了上面注解以后只需要在controller層需要注解的方法上加對(duì)應(yīng)注解即可

緩存生成鍵工具類(lèi)

/*** 緩存鍵生成工具*/ public class CacheKeyBuilder {/*** 生成key** @param key 鍵* @param params 參數(shù)* @param args 參數(shù)值* @return* @throws IllegalAccessException 當(dāng)訪問(wèn)異常時(shí)拋出*/public static String generate(String key, String params, Object[] args) throws IllegalAccessException {StringBuilder keyBuilder = new StringBuilder("");if (StringUtils.hasText(key)) {keyBuilder.append(key);}if (StringUtils.hasText(params)) {String paramsResult = ObjectAccessUtils.get(args, params, String.class, "_", "null");keyBuilder.append(":");keyBuilder.append(paramsResult);}return keyBuilder.toString();} }

自定義緩存攔截器

注意這里的Interceptor是org.aopalliance.intercept包下的
Spring的AOP只能支持到方法級(jí)別的切入。換句話說(shuō),切入點(diǎn)只能是某個(gè)方法。

package com.itheima.j2cache.aop;import com.itheima.j2cache.annotation.Cache; import com.itheima.j2cache.annotation.CacheEvictor; import com.itheima.j2cache.aop.processor.AbstractCacheAnnotationProcessor; import com.itheima.j2cache.aop.processor.CacheEvictorAnnotationProcessor; import com.itheima.j2cache.aop.processor.CachesAnnotationProcessor; import com.itheima.j2cache.utils.SpringApplicationContextUtils; import org.aopalliance.intercept.Interceptor; 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.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.Import; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.stereotype.Component;import java.lang.reflect.Method;/*** 緩存操作攔截器*/@Aspect @Component @EnableAspectJAutoProxy(proxyTargetClass = true)//指定使用cglib方式為Controller創(chuàng)建代理對(duì)象,代理對(duì)象其實(shí)是目標(biāo)對(duì)象的子類(lèi) @Import(SpringApplicationContextUtils.class) public class CacheMethodInterceptor implements Interceptor{/*** 攔截方法上使用Cache注解的Controller* @param proceedingJoinPoint* @return* @throws Throwable*/@Around("@annotation(com.itheima.j2cache.annotation.Cache)")//環(huán)繞通知//@Around注解,表示這是一個(gè)環(huán)繞通知。環(huán)繞通知是所有通知里功能最為強(qiáng)大的通知,可以實(shí)現(xiàn)前置通知、后置通知、異常通知以及返回通知的功能。目標(biāo)方法進(jìn)入環(huán)繞通知后,通過(guò)調(diào)用ProceedingJoinPoint對(duì)象的proceed方法使目標(biāo)方法繼續(xù)執(zhí)行,開(kāi)發(fā)者可以在此修改目標(biāo)方法的執(zhí)行參數(shù)、返回值等,并且可以在此處理目標(biāo)方法的異常。public Object invokeCacheAllMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{//獲得方法前面對(duì)象MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();//獲得當(dāng)前攔截到的Controller方法對(duì)象Method method = signature.getMethod();//獲得方法上的Cache注解信息Cache cache = AnnotationUtils.findAnnotation(method, Cache.class);if(cache != null){System.out.println("需要進(jìn)行設(shè)置緩存數(shù)據(jù)處理...");//創(chuàng)建處理器,具體處理緩存邏輯CachesAnnotationProcessor processor = AbstractCacheAnnotationProcessor.getProcessor(proceedingJoinPoint, cache);return processor.process(proceedingJoinPoint);}//沒(méi)有獲取到Cache注解信息,直接放行return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());}/*** 攔截方法上使用CacheEvictor注解的Controller* @param proceedingJoinPoint* @return* @throws Throwable*/@Around("@annotation(com.itheima.j2cache.annotation.CacheEvictor)")//環(huán)繞通知public Object invokeCacheEvictorAllMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();Method method = signature.getMethod();CacheEvictor cacheEvictor = AnnotationUtils.findAnnotation(method, CacheEvictor.class);if(cacheEvictor != null){System.out.println("清理緩存處理...");//創(chuàng)建清理緩存的處理器CacheEvictorAnnotationProcessor processor = AbstractCacheAnnotationProcessor.getProcessor(proceedingJoinPoint, cacheEvictor);return processor.process(proceedingJoinPoint);}return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());}}

在上面的攔截器中使用了 CachesAnnotationProcessor processor = AbstractCacheAnnotationProcessor.getProcessor(proceedingJoinPoint, cache);來(lái)對(duì)緩存進(jìn)行處理,需要自定義緩存處理器:

緩存處理器

import com.itheima.j2cache.annotation.Cache; import com.itheima.j2cache.annotation.CacheEvictor; import com.itheima.j2cache.model.AnnotationInfo; import com.itheima.j2cache.utils.CacheKeyBuilder; import com.itheima.j2cache.utils.SpringApplicationContextUtils; import net.oschina.j2cache.CacheChannel; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.context.ApplicationContext; import org.springframework.util.StringUtils;/*** 抽象緩存注解處理器*/ public abstract class AbstractCacheAnnotationProcessor {protected CacheChannel cacheChannel;/*** 初始化公共屬性,供子類(lèi)使用*///注意這里使用應(yīng)用上下文來(lái)獲得對(duì)應(yīng)的CacheChannel這個(gè)beanpublic AbstractCacheAnnotationProcessor(){ApplicationContext applicationContext = SpringApplicationContextUtils.getApplicationContext();cacheChannel = applicationContext.getBean(CacheChannel.class);}/*** 封裝注解信息* @param proceedingJoinPoint* @param cache* @return*/protected AnnotationInfo<Cache> getAnnotationInfo(ProceedingJoinPoint proceedingJoinPoint,Cache cache){AnnotationInfo<Cache> annotationInfo = new AnnotationInfo<>();annotationInfo.setAnnotation(cache);annotationInfo.setRegion(cache.region());try{annotationInfo.setKey(generateKey(proceedingJoinPoint,cache));}catch (Exception e){e.printStackTrace();}return annotationInfo;}/*** 動(dòng)態(tài)解析注解信息,生成key* @param proceedingJoinPoint* @param cache* @return*/protected String generateKey(ProceedingJoinPoint proceedingJoinPoint,Cache cache) throws IllegalAccessException{String key = cache.key();//abif(!StringUtils.hasText(key)){//如果當(dāng)前key為空串,重新設(shè)置當(dāng)前可以為:目標(biāo)Controller類(lèi)名:方法名String className = proceedingJoinPoint.getTarget().getClass().getSimpleName();MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();String methodName = signature.getMethod().getName();key = className + ":" + methodName;}//ab:100key = CacheKeyBuilder.generate(key,cache.params(),proceedingJoinPoint.getArgs());return key;}/*** 抽象方法,處理緩存操作,具體應(yīng)該由子類(lèi)具體實(shí)現(xiàn)* @param proceedingJoinPoint* @return* @throws Throwable*/public abstract Object process(ProceedingJoinPoint proceedingJoinPoint) throws Throwable;/*** 獲得緩存注解處理器對(duì)象* @param proceedingJoinPoint* @param cache* @return*/public static CachesAnnotationProcessor getProcessor(ProceedingJoinPoint proceedingJoinPoint, Cache cache){return new CachesAnnotationProcessor(proceedingJoinPoint,cache);}/*** 獲得清理緩存注解處理器對(duì)象* @param proceedingJoinPoint* @param cacheEvictor* @return*/public static CacheEvictorAnnotationProcessor getProcessor(ProceedingJoinPoint proceedingJoinPoint, CacheEvictor cacheEvictor){return new CacheEvictorAnnotationProcessor(proceedingJoinPoint,cacheEvictor);} }

清理緩存注解的處理器:

/*** 清理緩存數(shù)據(jù)處理器*/ public class CacheEvictorAnnotationProcessor extends AbstractCacheAnnotationProcessor{/*** 封裝注解信息集合*/private List<AnnotationInfo<Cache>> cacheList = new ArrayList<>();/*** 初始化清理緩存注解處理器對(duì)象,同時(shí)初始化一些緩存操作的對(duì)象* @param proceedingJoinPoint* @param cacheEvictor*/public CacheEvictorAnnotationProcessor(ProceedingJoinPoint proceedingJoinPoint, CacheEvictor cacheEvictor) {super();Cache[] value = cacheEvictor.value();for(Cache cache : value){AnnotationInfo<Cache> annotationInfo = getAnnotationInfo(proceedingJoinPoint, cache);cacheList.add(annotationInfo);}}/*** 具體清理緩存處理邏輯* @param proceedingJoinPoint* @return* @throws Throwable*/public Object process(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{for (AnnotationInfo<Cache> annotationInfo : cacheList) {String region = annotationInfo.getRegion();String key = annotationInfo.getKey();//清理緩存數(shù)據(jù)cacheChannel.evict(region,key);}//調(diào)用目標(biāo)方法(就是Controller中的方法)return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());} }

緩存注解處理器:

/*** 緩存注解處理器*/ public class CachesAnnotationProcessor extends AbstractCacheAnnotationProcessor {private static final Logger logger = LoggerFactory.getLogger(CachesAnnotationProcessor.class);private AnnotationInfo<Cache> annotationInfo;/*** 初始化處理器,同時(shí)將相關(guān)的對(duì)象進(jìn)行初始化* @param proceedingJoinPoint* @param cache*/public CachesAnnotationProcessor(ProceedingJoinPoint proceedingJoinPoint, Cache cache) {super();//創(chuàng)建注解信息對(duì)象annotationInfo = getAnnotationInfo(proceedingJoinPoint,cache);}/*** 具體緩存處理邏輯* @param proceedingJoinPoint* @return* @throws Throwable*/public Object process(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{Object result = null;boolean existsCache = false;//1、獲取緩存數(shù)據(jù)CacheHolder cacheHolder = getCache(annotationInfo);if(cacheHolder.isExistsCache()){//2、如果緩存數(shù)據(jù)存在則直接返回(相當(dāng)于controller的目標(biāo)方法沒(méi)有執(zhí)行)result = cacheHolder.getValue();//緩存結(jié)果數(shù)據(jù)existsCache = true;}if(!existsCache){//3、如何緩存數(shù)據(jù)不存在,放行調(diào)用Controller的目標(biāo)方法result = invoke(proceedingJoinPoint);//4、將目標(biāo)方法的返回值載入緩存setCache(result);}//5、將結(jié)果返回return result;}/*** 獲取緩存數(shù)據(jù)* @param annotationInfo* @return*/private CacheHolder getCache(AnnotationInfo<Cache> annotationInfo){Object value = null;String region = annotationInfo.getRegion();String key = annotationInfo.getKey();boolean exists = cacheChannel.exists(region, key);if(exists){CacheObject cacheObject = cacheChannel.get(region, key);value = cacheObject.getValue();//獲得緩存結(jié)果數(shù)據(jù)return CacheHolder.newResult(value,true);}return CacheHolder.newResult(value,false);}/*** 調(diào)用目標(biāo)方法* @param proceedingJoinPoint* @return*/private Object invoke(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());}/*** 設(shè)置緩存數(shù)據(jù)* @param result*/private void setCache(Object result){cacheChannel.set(annotationInfo.getRegion(),annotationInfo.getKey(),result);} }

在上面的處理器中用 return CacheHolder.newResult(value,true);來(lái)獲得緩存結(jié)果,需要自定義一個(gè)結(jié)果封裝類(lèi)

緩存結(jié)果和緩存信息實(shí)體封裝

緩存信息封裝

/*** Cache相關(guān)信息封裝*/ public class AnnotationInfo<T extends Annotation> {private T annotation;private String region;private String key;//region:key:paramspublic T getAnnotation() {return annotation;}public void setAnnotation(T annotation) {this.annotation = annotation;}public String getRegion() {return region;}public void setRegion(String region) {this.region = region;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}public String toString() {if (annotation == null) {return null;}return JSONObject.toJSONString(this);} }

緩存結(jié)果封裝

/*** 緩存結(jié)果封裝*/ public class CacheHolder {private Object value;//緩存的數(shù)據(jù)private boolean existsCache;//緩存數(shù)據(jù)是否存在private Throwable throwable;/*** 初始化緩存占位*/private CacheHolder() {}/*** 獲取值** @return*/public Object getValue() {return value;}/*** 是否存在緩存** @return*/public boolean isExistsCache() {return existsCache;}/*** 是否有錯(cuò)誤** @return*/public boolean hasError() {return throwable != null;}/*** 生成緩存結(jié)果的占位** @param value 結(jié)果* @param existsCache 是否存在緩存* @return 緩存*/public static CacheHolder newResult(Object value, boolean existsCache) {CacheHolder cacheHolder = new CacheHolder();cacheHolder.value = value;cacheHolder.existsCache = existsCache;return cacheHolder;}/*** 生成緩存異常的占位** @param throwable 異常* @return 緩存*/public static CacheHolder newError(Throwable throwable) {CacheHolder cacheHolder = new CacheHolder();cacheHolder.throwable = throwable;return cacheHolder;} }

開(kāi)啟聲明式注解

/*** 開(kāi)啟聲明式緩存功能*/@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @Import(CacheMethodInterceptor.class) public @interface EnableCache { }

注意自定義這個(gè)注解以后在主啟動(dòng)類(lèi)上加@EnableCache即可表示開(kāi)啟注解

controller層使用緩存

/*** 地址簿*/ @Log4j2 @RestController @RequestMapping("addressBook") public class AddressBookController {@Autowiredprivate IAddressBookService addressBookService;@Autowiredprivate CacheChannel cacheChannel;private String region = "addressBook";/*** 新增地址簿** @param entity* @return*/@PostMapping("")public Result save(@RequestBody AddressBook entity) {if (1 == entity.getIsDefault()) {addressBookService.lambdaUpdate().set(AddressBook::getIsDefault, 0).eq(AddressBook::getUserId, entity.getUserId()).update();}boolean result = addressBookService.save(entity);if (result) {//載入緩存cacheChannel.set(region,entity.getId(),entity);return Result.ok();}return Result.error();}/*** 查詢(xún)地址簿詳情** @param id* @return*/@GetMapping("detail/{id}")@Cache(region = "addressBook",key = "ab",params = "id")public AddressBook detail(@PathVariable(name = "id") String id) {AddressBook addressBook = addressBookService.getById(id);return addressBook;}/*** 分頁(yè)查詢(xún)** @param page* @param pageSize* @param userId* @return*/@GetMapping("page")public PageResponse<AddressBook> page(Integer page, Integer pageSize, String userId, String keyword) {Page<AddressBook> iPage = new Page(page, pageSize);Page<AddressBook> pageResult = addressBookService.lambdaQuery().eq(StringUtils.isNotEmpty(userId), AddressBook::getUserId, userId).and(StringUtils.isNotEmpty(keyword), wrapper ->wrapper.like(AddressBook::getName, keyword).or().like(AddressBook::getPhoneNumber, keyword).or().like(AddressBook::getCompanyName, keyword)).page(iPage);return PageResponse.<AddressBook>builder().items(pageResult.getRecords()).page(page).pagesize(pageSize).pages(pageResult.getPages()).counts(pageResult.getTotal()).build();}/*** 修改** @param id* @param entity* @return*/@PutMapping("/{id}")@CacheEvictor(value = {@Cache(region = "addressBook",key = "ab",params = "1.id")})public Result update(@PathVariable(name = "id") String id, @RequestBody AddressBook entity) {entity.setId(id);if (1 == entity.getIsDefault()) {addressBookService.lambdaUpdate().set(AddressBook::getIsDefault, 0).eq(AddressBook::getUserId, entity.getUserId()).update();}boolean result = addressBookService.updateById(entity);if (result) {return Result.ok();}return Result.error();}/*** 刪除** @param id* @return*/@DeleteMapping("/{id}")@CacheEvictor({@Cache(region = "addressBook",key = "ab",params = "id")})public Result del(@PathVariable(name = "id") String id) {boolean result = addressBookService.removeById(id);if (result) {return Result.ok();}return Result.error();} }

總結(jié)

使用aspectj:AOP 技術(shù)利用一種稱(chēng)為"橫切"的技術(shù),剖解開(kāi)封裝的對(duì)象內(nèi)部,并將那些影響了多個(gè)類(lèi)的公共行為封裝到一個(gè)可重用模塊,并將其命名為"Aspect",即切面。所謂"切面",簡(jiǎn)單說(shuō)就是那些與業(yè)務(wù)無(wú)關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任封裝起來(lái),便于減少系統(tǒng)的重復(fù)代碼,降低模塊之間的耦合度,并有利于未來(lái)的可操作性和可維護(hù)性。
這里的切面即用戶(hù)請(qǐng)求時(shí)先查詢(xún)緩存這一過(guò)程。
注意:這里使用的是aspectj而非Springaop,故使用時(shí)用法有不一樣。
使用j2cache框架的整體邏輯:自定義緩存注解,類(lèi)似springboot自帶的cache,但是這里粒度更細(xì),而且更好控制超時(shí)時(shí)間

緩存層類(lèi)似如下圖:

然后需要用到aspectj的aop邏輯,自定義橫切關(guān)注點(diǎn),這里的連接點(diǎn)即是controller層的方法,需要判斷每個(gè)方法上是否存在cahce注解,如果不存在則直接放行( proceedingJoinPoint.proceed),如果存在則交給緩存處理器進(jìn)行處理,這里添加和刪除緩存主要用的是j2cache組件的cachechannel,個(gè)人理解它這里類(lèi)似一個(gè)連接到緩存服務(wù)器的通道,且有相應(yīng)的api可以供增刪操作(cacheChannel.set(annotationInfo.getRegion(),annotationInfo.getKey(),result))。在讀取緩存時(shí)首先是從一級(jí)緩存中取,然后從二級(jí)緩存中取,如果沒(méi)找到則查詢(xún)數(shù)據(jù)庫(kù)。對(duì)于緩存結(jié)果的獲得通過(guò)封裝一個(gè)緩存結(jié)果類(lèi)和獲得cache注解的信息類(lèi)來(lái)獲得( AnnotationInfo ,制定了這個(gè)類(lèi)的數(shù)據(jù)類(lèi)型是Annotation的子類(lèi))。

總結(jié)

以上是生活随笔為你收集整理的springboot使用j2cache框架和aspectj自定义缓存的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 男人操女人网站 | 美女扒开腿让男生桶 | 啪啪五月天 | 91超碰免费在线 | 国产美女在线免费观看 | 成人在线免费观看视频 | 黑丝美女av | 一卡二卡三卡四卡 | 最新免费av网站 | 免费在线观看网址 | 日本一卡二卡在线 | 免费在线观看毛片视频 | 男人的天堂在线视频 | 狠狠欧美 | 91精品啪在线观看国产线免费 | 国产裸体无遮挡 | 香蕉大人久久国产成人av | 亚洲在线播放 | 亚洲欧美日韩在线看 | 亚洲一区二区在线免费观看 | 99re中文字幕 | 午夜啪啪福利 | 97网站 | 国产精品无码成人片 | 国产激情无码一区二区三区 | 可以免费看的毛片 | 男生插女生视频在线观看 | 99热这里只有精品5 国产精品伦子伦免费视频 精品一二三 | 国产aⅴ一区二区三区 | 国产日韩欧美亚洲 | 精品人妻一区二区三区四区久久 | 在线视频资源 | 日本电车痴汉 | 性综合网 | 中文字幕一区二区三区人妻不卡 | 一级美女大片 | 日韩精品电影网 | 一区二区三区黄色 | 爆操欧美美女 | 成年人免费在线看 | 久久久久久av无码免费网站 | 亚洲激情视频在线观看 | 免费人成网站 | 成年人视频在线看 | 日韩电影中文字幕在线观看 | 毛片xxx| 午夜在线精品 | 午夜久久久久 | av日韩精品 | 亚洲最大的成人网站 | 樱桃视频一区二区三区 | 国产在线播 | 小泽玛利亚一区二区三区 | 日本韩国欧美一区二区三区 | 国产在线成人精品午夜 | 国产欧美一区二区三区四区 | 久草中文在线视频 | 亚洲成在线| 借种(出轨高h) | 亚洲精品福利在线观看 | 精品欧美一区二区久久久久 | 国产无遮挡呻吟娇喘视频 | 国产高清自拍一区 | www成人免费| 理论片在线观看视频 | 中文字幕理伦片免费看 | 欧美久草| 91久操| 成人伊人网 | 人人97| 久久久精品人妻无码专区 | 日韩影院一区 | www.黄在线观看 | 国产第四页 | 午夜av导航 | 少妇在线播放 | 国产一区二区福利 | 亚洲免费视 | 日日干干 | 亚洲国产第一 | 成人黄色国产 | 精品免费在线观看 | 亚洲成人av网址 | 日韩福利一区二区 | 国产精品一区二区三区久久 | 伊人久久久久久久久久 | 亚洲av无码一区东京热久久 | 亚洲 欧美 综合 | 人人干网站 | 操操操免费视频 | 91视频这里只有精品 | 国产极品尤物 | 欧美日在线 | 鸭子av| 免费成人精品 | 青青操原| 香蕉视频2020 | 在线a网 | 亚洲第一中文字幕 |