赞
踩
查询频率高、更新频率低的数据可以加缓存,缓存可分为本地缓存、分布式缓存2大类。
l
本地缓存
本地缓存常见实现
分布式缓存
分布式缓存常见实现
springboot 定义了一套缓存标准,提供了默认实现,也可以引入第三方的缓存实现。
1、pom.xml
创建项目时勾选 I/O -> Spring cache abstraction,或自行添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
2、启动类加 @EnableCaching
可以在 yml 中配置,也可以用 java 代码配置
spring:
cache:
#缓存类型,参见CacheType,缺省时默认为 SIMPLE
type: SIMPLE
#缓存名称,list,需要在此处列出所有用到的缓存名称
cache-names: userInfo,systemConfig
# 一些缓存类型可指定扩展配置,参见 CacheProperties 中对应的静态类的属性
# caffeine:
# spec: initialCapacity=100,maximumSize=1000,expireAfterAccess=1800s
常用的缓存类型:CAFFEINE、EHCACHE、REDIS、SIMPLE(基于ConcurrentMap实现,无需引入第三方缓存实现框架)、NONE(不使用缓存)。
org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration 源码如下
@Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(CacheManager.class) //未配置缓存管理器时默认使用 Simple @Conditional(CacheCondition.class) class SimpleCacheConfiguration { @Bean ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers cacheManagerCustomizers) { ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager(); List<String> cacheNames = cacheProperties.getCacheNames(); if (!cacheNames.isEmpty()) { cacheManager.setCacheNames(cacheNames); } return cacheManagerCustomizers.customize(cacheManager); } }
@Service public class UserService { @Resource private UserDao userDao; @Cacheable(cacheNames = "userInfo", key = "#id") public User getUserById(Long id) { return userDao.getUserById(id); } @CacheEvict(cacheNames = "userInfo", key = "#user.id") public void updateUserInfo(User user) { userDao.updateUserInfo(user); } @CacheEvict(cacheNames = "userInfo", key = "#id") public void deleteById(Long id) { userDao.deleteById(id); } }
缓存注解
以上注解都是在目标方法执行完毕后才写入、删除缓存,如果方法中抛出异常,则不写入、删除缓存。
缓存注解的属性
key、condition、unless 都可以使用SpEL取值,可以使用内置对象,常见的内置对象如下
CacheManager 提供了一系列操作缓存的方法,此处可以自行封装为缓存工具类,示例
import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Nullable; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import javax.annotation.Resource; /** * 统一缓存服务 */ @Slf4j @Service public class CommonCacheService { @Resource private CacheManager cacheManager; /** * 清除指定的key,可能会以异步之类的方式延迟执行 * * @param cacheName 缓存名称 * @param cacheKey 缓存key */ public void delayClear(String cacheName, String cacheKey) { Assert.isTrue(StringUtils.isNotBlank(cacheKey), "cacheKey不能为空"); Cache cache = this.getCacheNotNull(cacheName); cache.evict(cacheKey); } /** * 清除指定的key,立即执行 * * @param cacheName 缓存名称 * @param cacheKey 缓存key */ public void clear(String cacheName, String cacheKey) { Assert.isTrue(StringUtils.isNotBlank(cacheKey), "cacheKey不能为空"); Cache cache = this.getCacheNotNull(cacheName); cache.evictIfPresent(cacheKey); } /** * 清除缓存名称下所有的key,可能会以异步之类的方式延迟执行 * * @param cacheName 缓存名称 */ public void delayClearAll(String cacheName) { Cache cache = this.getCacheNotNull(cacheName); cache.clear(); } /** * 清除缓存名称下所有的key,立即执行 * * @param cacheName 缓存名称 */ public void clearAll(String cacheName) { Cache cache = this.getCacheNotNull(cacheName); cache.invalidate(); } /** * 设置或更新value,可能会以异步之类的方式延迟执行 * * @param cacheName 缓存名称 * @param cacheKey 缓存key * @param value 值 */ public void delayPut(String cacheName, String cacheKey, Object value) { Assert.isTrue(StringUtils.isNotBlank(cacheKey), "cacheKey不能为空"); Cache cache = this.getCacheNotNull(cacheName); cache.put(cacheKey, value); } /** * 设置或更新value,立即执行 * * @param cacheName 缓存名称 * @param cacheKey 缓存key * @param value 值 */ public void put(String cacheName, String cacheKey, Object value) { Assert.isTrue(StringUtils.isNotBlank(cacheKey), "cacheKey不能为空"); Cache cache = this.getCacheNotNull(cacheName); cache.putIfAbsent(cacheKey, value); } /** * 获取指定key对应的value * * @param cacheName 缓存名称 * @param cacheKey 缓存key * @param clazz 目标类型的class对象 * @param <T> 目标类型 * @return T */ @Nullable public <T> T get(String cacheName, String cacheKey, Class<T> clazz) { Assert.isTrue(StringUtils.isNotBlank(cacheKey), "cacheKey不能为空"); Cache cache = this.getCacheNotNull(cacheName); return cache.get(cacheKey, clazz); } /** * 获取指定key对应的value(String类型) * * @param cacheName 缓存名称 * @param cacheKey 缓存key * @return String */ @Nullable public String get(String cacheName, String cacheKey) { return this.get(cacheName, cacheKey, String.class); } private Cache getCacheNotNull(String cacheName) { Assert.isTrue(StringUtils.isNotBlank(cacheName), "cacheName不能为空"); Cache cache = cacheManager.getCache(cacheName); Assert.notNull(cache, "指定的cache不存在,cacheName=" + cacheName); return cache; } }
1、pom.xml
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
2、缓存配置
方式一 yml
spring:
cache:
type: caffeine
cache-names: userInfo,systemConfig
caffeine:
spec: initialCapacity=100,maximumSize=1000,expireAfterAccess=5s
spec是针对所有缓存的设置,不能针对各个缓存分别进行配置,比较死板。
3种缓存淘汰策略
方式二 配置类(推荐)
import com.github.benmanes.caffeine.cache.Caffeine; import org.springframework.cache.CacheManager; import org.springframework.cache.caffeine.CaffeineCache; import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Arrays; import java.util.concurrent.TimeUnit; @Configuration public class CacheConfig { @Bean public CacheManager cacheManager() { CaffeineCache userInfoCache = this.buildCache("userInfo", 60, 100, 10000); CaffeineCache systemConfigCache = this.buildCache("systemConfig", 30, 10, 1000); SimpleCacheManager manager = new SimpleCacheManager(); manager.setCaches(Arrays.asList(userInfoCache, systemConfigCache)); return manager; } private CaffeineCache buildCache(String cacheName, int expireSecondsAfterWrite, int initialCapacity, long maximumSize) { return new CaffeineCache(cacheName, Caffeine.newBuilder() .expireAfterWrite(expireSecondsAfterWrite, TimeUnit.SECONDS) .initialCapacity(initialCapacity) .maximumSize(maximumSize) .build()); } }
1、pom.xml
<!-- ehcache3.x -->
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.9.0</version>
</dependency>
<!-- ehcahce 2.x,已不再维护 -->
<!--<dependency>-->
<!-- <groupId>net.sf.ehcache</groupId>-->
<!-- <artifactId>ehcache</artifactId>-->
<!-- <version>2.10.6</version>-->
<!--</dependency>-->
2、resources下新建ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <!-- 磁盘缓存位置。java.io.tmpdir是系统默认的临时文件目录,也可以使用自定义的路径 --> <diskStore path="java.io.tmpdir"/> <!-- 默认缓存管理器 --> <!-- memoryStoreEvictionPolicy缓存淘汰策略,支持FIFO、LRU、LFU --> <!-- maxElementsInMemory内存中的元素最大数量,overflowToDisk内存元素数量达到最大值时是否存储到硬盘 --> <!-- timeToLiveSeconds缓存有效期,timeToIdleSeconds缓存有效期内多久未访问就自动清除 --> <defaultCache memoryStoreEvictionPolicy="LRU" maxElementsInMemory="1000" overflowToDisk="false" timeToLiveSeconds="10" timeToIdleSeconds="5"/> <!-- 自定义缓存管理器 --> <cache name="userInfo" memoryStoreEvictionPolicy="LRU" maxElementsInMemory="1000" overflowToDisk="false" timeToLiveSeconds="10" timeToIdleSeconds="5"/> <cache name="systemConfig" memoryStoreEvictionPolicy="LRU" maxElementsInMemory="1000" overflowToDisk="false" timeToLiveSeconds="10" timeToIdleSeconds="5"/> </ehcache>
这是ehcache2.x的配置方式,3.x向下兼容2.x的配置方式
3、yml
spring:
cache:
#指定ehcache配置文件位置
jcache:
config: classpath:ehcache.xml
# ehcache:
# config: classpath:ehcache.xml
3.x用jcache.config,2.x使用ehcache.config。3.x向下兼容2.x的配置方式,也可以使用ehcache.config。
1、pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、yml
spring: #redis配置 redis: host: 192.168.1.1 #集群则使用 cluster.nodes: 192.168.1.1:6379,192.168.1.2:6379,192.168.1.3:6379 port: 6379 database: 0 timeout: 3000 #缓存配置 cache: type: REDIS cache-names: userInfo,systemConfig redis: #是否使用key前缀 use-key-prefix: true key-prefix: mall_ #是否缓存null值 cache-null-values: false #缓存有效期 time-to-live: 300s
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。