一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 使用Spring Cache設置緩存條件操作

使用Spring Cache設置緩存條件操作

2021-12-31 13:14梁云亮 Java教程

這篇文章主要介紹了使用Spring Cache設置緩存條件操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

Spring Cache設置緩存條件

原理

從Spring3.1開始,Spring框架提供了對Cache的支持,提供了一個對緩存使用的抽象,通過在既有代碼中添加少量它定義的各種 annotation,即能夠達到緩存方法的返回對象的作用。

提供的主要注解有@Cacheable、@CachePut、@CacheEvict和@Caching,具體見下表:

注解 說明
@Cacheable 可以標注在類或方法上:標注在方法上表示該方法支持數據緩存;標在類上表示該類的所有方法都支持數據緩存。 具體功能:在執行方法體之前,檢查緩存中是否有相同key值的緩存存在,如果存在對應的緩存,直接返回緩存中的值;如果不存在對應的緩存,則執行相應的方法體獲取數據,并將數據存儲到緩存中。
@CachePut 可以標注在類或方法上,表示支持數據緩存。 具體功能:在方法執行前不會檢查緩存中是否存在相應的緩存,而是每次都會執行方法體,并將方法執行結果存儲到緩存中,如果相應key值的緩存存在,則更新key對應的value值。
@CacheEvict 可以標注在類或方法上,用于清除相應key值的緩存。
@Caching 可以標注在類或方法上,它有三個屬性cacheable、put、evict分別用于指定@Cacheable、@CachePut和@CacheEvict

當需要在類上或方法上同時使用多個注解時,可以使用@Caching,如:

?
1
@Caching(cacheable=@Cacheable("User"), evict = {@CacheEvict("Member"), @CacheEvict(value = "Customer", allEntries = true)})

@Cacheable的常用屬性及說明

如下表所示:

@Cacheable屬性 說明
key 表示緩存的名稱,必須指定且至少要有一個值,比如:@Cacheable(value=“Dept”)或@Cacheable(value={“Dept”,“Depts”})
condition 表示是否需要緩存,默認為空,表示所有情況都會緩存。通過SpEL表達式來指定,若condition的值為true則會緩存,若為false則不會緩存,如@Cacheable(value=“Dept”,key="‘deptno_'+# deptno “,condition=”#deptno<=40")
value 表示緩存的key,支持SpEL表達式,如@Cacheable(value=“Dept”,key="‘deptno_' +#deptno"),可以不指定值,如果不指定,則缺省按照方法的所有參數進行組合。除了上述使用方法參數作為key之外,Spring還提供了一個root對象用來生成key,使用方法如下表所示,其中"#root"可以省略。

Root對象

Root對象 說明
methodName 當前方法名,比如#root.methodName
method 當前方法,比如#root.method.name
target 當前被調用的對象,比如#root.target
targetClass 當前被調用的對象的class,比如#root.targetClass
args 當前方法參數組成的數組,比如#root.args[0]
caches 當前被調用的方法使用的緩存,比如#root.caches[0].name

@CachePut的常用屬性同@Cacheable

@CacheEvict的常用屬性如下表所示:

@CacheEvict屬性 說明
value 表示要清除的緩存名
key 表示需要清除的緩存key值,
condition 當condition的值為true時才清除緩存
allEntries 表示是否需要清除緩存中的所有元素。默認為false,表示不需要,當指定了allEntries為true時,將忽略指定的key。
beforeInvocation 清除操作默認是在方法成功執行之后觸發的,即方法如果因為拋出異常而未能成功返回時不會觸發清除操作。使用beforeInvocation可以改變觸發清除操作的時間,當該屬性值為true時,會在調用該方法之前清除緩存中的指定元素。


示例:設置當 dname 的長度大于3時才緩存

?
1
2
3
4
5
6
7
8
9
10
//條件緩存
@ResponseBody
@GetMapping("/getLocByDname")
@Cacheable(cacheNames = "dept", key = "#dname", condition = "#dname.length()>3")
public String getLocByDname(@RequestParam("dname") String dname) {//key動態參數
    QueryWrapper<Dept> queryMapper = new QueryWrapper<>();
    queryMapper.eq("dname", dname);
    Dept dept = deptService.getOne(queryMapper);
    return dept.getLoc();
}

示例:unless 即條件不成立時緩存

#result 代表返回值,意思是當返回碼不等于 200 時不緩存,也就是等于 200 時才緩存。

?
1
2
3
4
5
6
7
8
9
10
11
12
@ResponseBody
@GetMapping("/getDeptByDname")
@Cacheable(cacheNames = "dept", key = "#dname", unless = "#result.code != 200")
public Result<Dept> getDeptByDname(@RequestParam("dname") String dname){//key動態參數
    QueryWrapper<Dept> queryMapper = new QueryWrapper<>();
    queryMapper.eq("dname", dname);
    Dept dept = deptService.getOne(queryMapper);
    if (dept == null)
        return ResultUtil.error(120, "dept is null");
    else
        return ResultUtil.success(dept);
}

Cache緩存配置

1、pom.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 反射工具類用于手動掃描指定包下的注解,根據defaultCache模塊增加ehcache緩存域(非Spring Cache必須)-->
<!-- https://mvnrepository.com/artifact/org.reflections/reflections -->
<dependency>
    <groupId>org.reflections</groupId>
    <artifactId>reflections</artifactId>
    <version>0.9.11</version>
</dependency>

2、Ehcache配置文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!-- 磁盤緩存位置 -->
    <diskStore path="java.io.tmpdir" />
    <!--
        name:緩存名稱。
        maxElementsInMemory:緩存最大個數。
        eternal:對象是否永久有效,一但設置了,timeout將不起作用。
        timeToIdleSeconds:設置對象在失效前的允許閑置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閑置時間無窮大。
        timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介于創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。
        overflowToDisk:當內存中對象數量達到maxElementsInMemory時,Ehcache將會對象寫到磁盤中。
        diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每個Cache都應該有自己的一個緩沖區。
        maxElementsOnDisk:硬盤最大緩存個數。
        diskPersistent:是否緩存虛擬機重啟期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
        diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。
        memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你可以設置為FIFO(先進先出)或是LFU(較少使用)。
        clearOnFlush:內存數量最大時是否清除。
    -->
    <!-- 默認緩存 -->
    <defaultCache
            eternal="false"
            maxElementsInMemory="200000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="0"
            timeToLiveSeconds="600"
            memoryStoreEvictionPolicy="LRU" />
</ehcache>

3、配置類

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
@Configuration
@EnableCaching
public class CustomConfiguration {
    /**
     * @see org.springframework.cache.interceptor.SimpleKeyGenerator
     * Generate a key based on the specified parameters.
     */
    public static Object generateKey(Object... params) {
        if (params.length == 0) {
            return SimpleKey.EMPTY;
        }
        if (params.length == 1) {
            Object param = params[0];
            if (param != null && !param.getClass().isArray()) {
                return param;
            }
        }
        return new SimpleKey(params);
    }
/**
 * 若將target作為key的一部分時,CGLIB動態代理可能導致重復緩存
 * 注意:返回的key一定要重寫hashCode()和toString(),防止key對象不一致導致的緩存無法命中
 * 例如:ehcache 底層存儲net.sf.ehcache.store.chm.SelectableConcurrentHashMap#containsKey
 */
    @Bean
    public KeyGenerator customKeyGenerator(){
        return (target, method, params) -> {
            final Object key = generateKey(params);
            StringBuffer buffer = new StringBuffer();
            buffer.append(method.getName());
            buffer.append("::");
            buffer.append(key.toString());
// 注意一定要轉為String,否則ehcache key對象可能不一樣,導致緩存無法命中
            return buffer.toString();
        };
    }
    /**
     * redis緩存管理器
     */
    @Bean
    @ConditionalOnBean(RedisConfiguration.class)
    @ConditionalOnProperty(prefix = "spring.cache", name = "type", havingValue = "redis",
            matchIfMissing = false)
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .entryTtl(Duration.ofMinutes(10));
        return RedisCacheManager
                .builder(RedisCacheWriter.lockingRedisCacheWriter(redisConnectionFactory))
                .cacheDefaults(config).build();
    }
/**
 * ehcache緩存管理器(默認)
 * default XML files {@link net.sf.ehcache.config.ConfigurationFactory#parseConfiguration()}
 */
    @Bean
    @ConditionalOnProperty(prefix = "spring.cache", name = "type", havingValue = "ehcache",
            matchIfMissing = true)
    public CacheManager ehcacheCacheManager() {
        net.sf.ehcache.CacheManager cacheManager = net.sf.ehcache.CacheManager.create();
        /**
         * 包掃描查找指定注解并將cacheNames添加到net.sf.ehcache.CacheManager(單例)
         */
        Reflections reflections = new Reflections("com.example.demo.service", new TypeAnnotationsScanner()
                , new SubTypesScanner(), new MethodAnnotationsScanner());
        Set<Class<?>> classesList = reflections.getTypesAnnotatedWith(CacheConfig.class);
        for (Class<?> aClass : classesList) {
            final CacheConfig config = AnnotationUtils.findAnnotation(aClass, CacheConfig.class);
            if (config.cacheNames() != null && config.cacheNames().length > 0) {
                for (String cacheName : config.cacheNames()) {
                    cacheManager.addCacheIfAbsent(cacheName);
                }
            }
        }
        /**
         * 方法級別的注解 @Caching、@CacheEvict、@Cacheable、@CachePut,結合實際業務場景僅掃描@Cacheable即可
         */
        final Set<Method> methods = reflections.getMethodsAnnotatedWith(Cacheable.class);
        for (Method method : methods) {
            final Cacheable cacheable = AnnotationUtils.findAnnotation(method, Cacheable.class);
            if (cacheable.cacheNames() != null && cacheable.cacheNames().length > 0) {
                for (String cacheName : cacheable.cacheNames()) {
                    cacheManager.addCacheIfAbsent(cacheName);
                }
            }
        }
        EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager();
        ehCacheCacheManager.setCacheManager(cacheManager);
        return ehCacheCacheManager;
    }
}

4、示例

?
1
2
3
4
5
6
7
8
9
10
11
12
@Component
@CacheConfig(cacheNames = "XXXServiceImpl", keyGenerator = "customKeyGenerator")
public class XXXServiceImpl extends ServiceImpl<XXXMapper, XXXEntity> implements XXXService {
    @CacheEvict(allEntries = true)
    public void evictAllEntries() {}
    @Override
    @Cacheable
    public List<XXXEntity> findById(Long id) {
        return this.baseMapper.selectList(new QueryWrapper<XXXEntity>().lambda()
                .eq(XXXEntity::getId, id));
    }
}

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://hcshow.blog.csdn.net/article/details/119271227

延伸 · 閱讀

精彩推薦
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
主站蜘蛛池模板: 成人精品视频一区二区在线 | 视频一区二区三区在线观看 | 日韩在线观看免费 | 好湿好紧太硬了我好爽 | 男人的天堂视频在线 | 香艳69xxxxx有声小说 | 4hc44四虎www在线影院男同 | 日本无遮挡吸乳视频看看 | 天天综合天天影视色香欲俱全 | 精品欧美一区二区三区四区 | 俄罗斯三级完整版在线观看 | 湿好紧太硬了我太爽了 | 粉嫩极品国产在线观看免费 | 东北老妇露脸xxxxx | 国产亚洲精品一区二区在线播放 | 精品一区二区三区在线成人 | 国产资源一区 | 国产乱码一卡二卡3卡四卡 国产乱插 | 亚洲天堂影视 | 免费超级乱淫视频播放性 | 国产性做久久久久久 | 国产成人综合一区精品 | 国产成人综合手机在线播放 | 日韩国产欧美精品综合二区 | 2019男人天堂 | 亚洲欧美在线免费 | 国产精品 视频一区 二区三区 | 亚洲男人的天堂视频 | 99影视在线视频免费观看 | 色中色导航| 男人的天堂在线观看视频不卡 | 久久偷拍免费2017 | 精品久久久久久无码人妻国产馆 | 日韩成人精品 | 久久re亚洲在线视频 | 久久天天躁狠狠躁夜夜躁 | 亚洲国产一区二区a毛片 | 国模孕妇季玥全部人体写真 | 母乳在线播放 | 久久国产加勒比精品无码 | 四虎影剧院 |