1 使用步骤
1.1 引入依赖与启动类注解
引入依赖,版本跟随Springboot即可
<!--ehcache缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
启动类增加@EnableCaching注解
@EnableJpaAuditing
@SpringBootApplication
@EnableScheduling
@EnableCaching
public class PCMSApplication {
public static void main(String[] args) {
SpringApplication.run(PCMSApplication.class, args);
}
}
1.2 新增Ehcache配置文件,并在application.properties文件配置
- Resources根目录下增加ehcache.xml文件
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<!--磁盘存储路径,当内存缓存满了的时候,就会往这里面放,java.io.tmdir是操作系统缓存的临时目录,不同操作系统缓存目录不一样。-->
<diskStore path="java.io.tmpdir"/>
<!--defaultCache:echcache的默认缓存策略 -->
<defaultCache
maxElementsInMemory="10000"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
<!--accessToken缓存策略-->
<!--
maxElementsInMemory 内存缓存中最多可以存放的元素数量,若放入Cache中的元素超过这个数值,则有以下两种情况
1)若overflowToDisk=true,则会将Cache中多出的元素放入磁盘文件中
2)若overflowToDisk=false,则根据memoryStoreEvictionPolicy策略替换Cache中原有的元素
overflowToDisk 内存不足时,是否启用磁盘缓存
eternal 缓存中对象是否永久有效
timeToIdleSeconds 缓存数据在失效前的允许闲置时间(单位:秒),仅当eternal=false时使用,默认值是0表示可闲置时间无穷大,若超过这个时间没有访问此Cache中的某个元素,那么此元素将被从Cache中清除
timeToLiveSeconds 缓存数据的总的存活时间(单位:秒),仅当eternal=false时使用,从创建开始计时,失效结束。
maxElementsOnDisk 磁盘缓存中最多可以存放的元素数量,0表示无穷大
diskExpiryThreadIntervalSeconds 磁盘缓存的清理线程运行间隔,默认是120秒
memoryStoreEvictionPolicy 内存存储与释放策略,即达到maxElementsInMemory限制时,Ehcache会根据指定策略清理内存 共有三种策略,分别为LRU(最近最少使用)、LFU(最常用的)、FIFO(先进先出)
-->
<cache name="DICTIONARY_CACHE"
maxElementsInMemory="1000000"
overflowToDisk="true"
timeToIdleSeconds="0"
timeToLiveSeconds="180000"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</cache>
</ehcache>
- application.properties增加配置
spring.cache.type=ehcache
1.3 引入工具类
- 普通工具类:支持获取缓存值,保存或更新缓存以及删除缓存
package com.gosun.pcms.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
/**
* @author yiqiang
* @date 2020/8/11 13:46
*/
@SuppressWarnings("WeakerAccess")
@Component
@Slf4j
@CacheConfig(cacheNames = {"DICTIONARY_CACHE"})
public class EhcacheUtils {
@Cacheable(key = "#keyName")
public Object getCache(String keyName){
log.info("[ EHCACHE ] 正在缓存 ==> Key: {}",keyName);
return null;
}
@CachePut(key="#keyName")
public <T> T updateCache(String keyName,T t){
log.info("[ EHCACHE ] 正在保存 ==> Key: {},Value: {}",keyName,t);
return t;
}
@CacheEvict(key = "#keyName")
public void delCache(String keyName){
log.info("[ EHCACHE ] 正在删除 ==> Key:{}",keyName);
}
}
- 工具类进一步封装:先尝试从缓存中获取,如果缓存中没有可以更换数据获取途径(比如数据库),再把获取的值存入缓存中
package com.gosun.pcms.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.function.Supplier;
/**
* @author yiqiang
* @date 2020/8/11 14:34
*/
@Component
@Slf4j
public class CacheUtil {
@Resource
private EhcacheUtils ehcacheUtils;
public Object cache(String keyName,Supplier supplier) {
Object cache = ehcacheUtils.getCache(keyName);
log.info("[ CacheUtil ] CACHE: {}",cache);
return cache==null?ehcacheUtils.updateCache(keyName,supplier.get()):cache;
}
}
2 结果展示
- 编写Controller,模拟普通字典表的获取过程
package com.gosun.pcms.controller;
import com.gosun.pcms.service.DetentionReasonService;
import com.gosun.pcms.util.CacheUtil;
import com.gosun.pcms.util.EhcacheUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author yiqiang
* @date 2020/8/7 17:38
*/
@RestController
@Api(value = "扣车理由字典", description = "扣车理由字典")
@RequestMapping(value = "/detentionReason")
@Slf4j
public class DetentionReasonController {
@Resource
private DetentionReasonService reasonService;
@Resource
private CacheUtil cacheUtil;
@GetMapping(value = "/getAll")
@ApiOperation(value = "获取全部:扣车理由字典")
public Object getAll() throws InterruptedException {
long t=System.currentTimeMillis();
Object detention_reason = cacheUtil.cache("detention_reason", reasonService::getAll);
log.info("耗时为: {}ms",System.currentTimeMillis()-t);
return detention_reason;
}
}
- 耗时展示:
从下图可以看出:首次获取走了数据库,耗时150ms,之后的请求都走了本地缓存,耗时0~1ms