SpringCache之本地缓存

针对不同的缓存技术,需要实现不同的cacheManager,Spring定义了如下的cacheManger实现。

|---------------------------|------------------------------------------------------------|
| CacheManger | 描述 |
| SimpleCacheManager | 使用简单的Collection来存储缓存,主要用于测试 |
| ConcurrentMapCacheManager | 使用ConcurrentMap作为缓存技术(默认),需要显式的删除缓存,无过期机制 |
| NoOpCacheManager | 仅测试用途,不会实际存储缓存 |
| EhCacheCacheManager | 使用EhCache作为缓存技术,以前在hibernate的时候经常用 |
| GuavaCacheManager | 使用google guava的GuavaCache作为缓存技术(1.5版本已不建议使用) |
| CaffeineCacheManager | 是使用Java8对Guava缓存的重写,spring5(springboot2)开始用Caffeine取代guava |
| HazelcastCacheManager | 使用Hazelcast作为缓存技术 |
| JCacheCacheManager | 使用JCache标准的实现作为缓存技术,如Apache Commons JCS |
| RedisCacheManager | 使用Redis作为缓存技术 |

常规的SpringBoot已经为我们自动配置了EhCache、Collection、Guava、ConcurrentMap等缓存,默认使用ConcurrentMapCacheManager。SpringBoot的application.properties配置文件,使用spring.cache前缀的属性进行配置。

使用

1.添加依赖

java 复制代码
   <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>

2.添加配置类

2.1 ConcurrentMapCacheManager,

spring默认就是ConcurrentMapCache,如果不指定缓存名称,可以不加配置类,直接@EnableCaching写道启动类上

java 复制代码
@EnableCaching
@Configuration
public class CacheConfig extends CachingConfigurerSupport {

    @Bean("ConcurrentMapCacheManager")
    @Primary
    public CacheManager caffeineCacheManager() {
        ConcurrentMapCacheManager concurrentMapCacheManager = new ConcurrentMapCacheManager();
        //可以事先指定chcheName
        //Collection<String> cacheNames = concurrentMapCacheManager.getCacheNames();
        //if (CollectionUtils.isEmpty(cacheNames)){
        //    集合
        //    concurrentMapCacheManager.setCacheNames();
        //}
        return concurrentMapCacheManager;
    }

}

2.2 caffeine

同理,如果不需要特殊参数,加入依赖后也可不写配置类

java 复制代码
<!-- 使用  caffeine https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine -->
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>2.6.0</version>
        </dependency>
java 复制代码
@EnableCaching
@Configuration
public class CacheConfig extends CachingConfigurerSupport {

    @Bean("caffeineCacheManager")
    @Primary
    public CacheManager caffeineCacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        // 方案一(常用):定制化缓存Cache
        cacheManager.setCaffeine(Caffeine.newBuilder()
                // 缓存项在写入后的过期时间为 5 分钟。
                .expireAfterWrite(5, TimeUnit.MINUTES)
                //设置缓存的初始容量为 100 个缓存项。
                .initialCapacity(100)
                //设置缓存的最大容量为 200 个缓存项。
                .maximumSize(200));
        return cacheManager;
    }
}

3.使用

主要基于Spring缓存注解@Cacheable、@CacheEvict、@CachePut的方式使用

  1. @Cacheable :改注解修饰的方法,若不存在缓存,则执行方法并将结果写入缓存;若存在缓存,则不执行方法,直接返回缓存结果。
  2. @CachePut :执行方法,更新缓存;该注解下的方法始终会被执行。
  3. @CacheEvict :删除缓存

3.1cacheable

调用这个方法的时候,会从缓存中查询,如果没有,查询数据库并将执行的结果存入缓存中,否则返回缓存中的对象。

|-----------|------------------------------------------------------------|-----------------------------------------------------------------|
| 参数 | 解释 | example |
| value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个,就是缓存的首个前缀 | 例如: @Cacheable(value="room") @Cacheable(value={"room1","room2"} |
| key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @Cacheable(value="room",key="#userId") |
| condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | @Cacheable(value=room",condition="#userId > 2") |

java 复制代码
@Component
public class UserCache {
    @Cacheable(cacheNames = "room", key = "#userId")
    public User getUserId(Interger userId){
        return queryuser();
    }
}

3.2 CachePut

主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用

|-----------|-------------------------------------------------------------------------------|------------------------------------------------------------------------------------|
| 参数 | 解释 | example |
| value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | @CachePut(value=room") |
| key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合,也可以使用返回值结果字段result | @CachePut(value="room",key="#userId") @CachePut(value="room",key="#result.userId") |
| condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | @CachePut(value="room",condition="#userId>2") |

java 复制代码
@Component
public class UserCache {
    @CachePut(cacheNames = "room", key = "#result.deptId+':'+#userId")
    public User getUserId(String userId){
       return queryuser();
    }

}

3.3@CachEvict

主要针对方法配置,能够根据一定的条件对缓存进行清空

|------------------|-----------------------------------------------------------------------------|------------------------------------------------------------------|
| 参数 | 解释 | example |
| value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | @CacheEvict(value="my cache") |
| key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @CacheEvict(value="testcache",key="#userName") |
| condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | @CacheEvict(value="testcache",condition="#userName.length()>2") |
| allEntries | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 | @CachEvict(value="testcache",allEntries=true) |
| beforeInvocation | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 | @CachEvict(value="testcache",beforeInvocation=true) |

java 复制代码
@Component
public class UserCache {

    @CacheEvict(cacheNames = "room")
    public User getUserId(String userId){
        return null;
    }

}

3.4 cacheManager的简单使用

java 复制代码
//获取缓存
Cache user = cacheManager.getCache("room");
//获取所有缓存数据
User nativeCache = (User)user.getNativeCache();
//获取某个key的数据
Object o1 = user.get("1").get();
//存入数据
 user.putIfAbsent(Object var1, @Nullable Object var2);
 user.put(Object var1, @Nullable Object var2);
//清空数据
user.evictIfPresent("room");

spring cache源码

java 复制代码
public interface Cache {
    String getName();

    Object getNativeCache();

    @Nullable
    ValueWrapper get(Object var1);

    @Nullable
    <T> T get(Object var1, @Nullable Class<T> var2);

    @Nullable
    <T> T get(Object var1, Callable<T> var2);

    void put(Object var1, @Nullable Object var2);

    @Nullable
    default ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
        ValueWrapper existingValue = this.get(key);
        if (existingValue == null) {
            this.put(key, value);
        }

        return existingValue;
    }

    void evict(Object var1);

    default boolean evictIfPresent(Object key) {
        this.evict(key);
        return false;
    }

    void clear();

    default boolean invalidate() {
        this.clear();
        return false;
    }

    public static class ValueRetrievalException extends RuntimeException {
        @Nullable
        private final Object key;

        public ValueRetrievalException(@Nullable Object key, Callable<?> loader, Throwable ex) {
            super(String.format("Value for key '%s' could not be loaded using '%s'", key, loader), ex);
            this.key = key;
        }

        @Nullable
        public Object getKey() {
            return this.key;
        }
    }

    @FunctionalInterface
    public interface ValueWrapper {
        @Nullable
        Object get();
    }
}

caffeine扩展的loadingCache

java 复制代码
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.github.benmanes.caffeine.cache;

import java.util.Map;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

public interface LoadingCache<K, V> extends Cache<K, V> {
    @Nullable V get(@NonNull K var1);

    @NonNull Map<@NonNull K, @NonNull V> getAll(@NonNull Iterable<? extends @NonNull K> var1);

    void refresh(@NonNull K var1);
}
相关推荐
m0_571957581 小时前
Java | Leetcode Java题解之第543题二叉树的直径
java·leetcode·题解
魔道不误砍柴功3 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2343 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨3 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
测开小菜鸟5 小时前
使用python向钉钉群聊发送消息
java·python·钉钉
P.H. Infinity6 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天6 小时前
java的threadlocal为何内存泄漏
java
caridle6 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^6 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋36 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx