Ehcache 是一个用 Java 实现的使用简单,高速,实现线程安全的缓存管理类库,Ehcache 提供了用内存,磁盘文件存储,以及分布式存储方式等多种灵活的 cache 管理方案,采用限制比较宽松的 Apache License V2.0 作为授权方式。Ehcache 从 Hibernate 发展而来,逐渐覆盖了 Cache 界的所有功能,是当前成长趋向不错的一个项目。它具有快速、简单易用、低消耗、强扩展性、依赖性低、支持缓存或元素的失效、支持对象或序列化缓存、支持内存缓存和磁盘缓存、提供了 FIFO、LRU、LFU 缓存策略、采用分布式缓存机制等特点。
在 pom.xml 文件中加入 spring-boot-starter-cache
和 ehcache
依赖包。
<!--spring 的缓存依赖,使用 spring 缓存机制必须加入的依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <!--集成 ehcache 需要的依赖--> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> </dependency> 复制代码
在资源文件(resource)目录下创建 ehcache.xml
配置文件,进行 Ehcache 的配置。
<?xml version="1.0" encoding="UTF-8"?> <ehcache> <!--默认的 ehcache 缓存配置--> <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" /> <!--指定缓存空间名称--> <cache name="user" maxElementsInMemory="1000" eternal="false" overflowToDisk="false" diskPersistent="false" timeToLiveSeconds="5" // 设置缓存有效时间为 5 秒 memoryStoreEvictionPolicy="LRU" /> </ehcache> 复制代码
在 application.properties 文件中,配置 ehcache.xml 文件的加载路径。
# ehcache 缓存配置 spring.cache.ehcache.config=classpath:config/ehcache.xml 复制代码
name:缓存名称。
maxElementsInMemory:缓存最大数目
maxElementsOnDisk:硬盘最大缓存个数。
eternal:对象是否永久有效,一旦设置了,timeout 将不起作用。
overflowToDisk:是否保存到磁盘,当系统宕机时,会存入本地磁盘。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当 eternal=false 对象不是永久有效时使用,可选属性,默认值是 0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。 最大时间介于创建时间和失效时间之间。仅当 eternal=false 对象不是永久有效时使用,默认是 0,也就是对象存活时间无穷大。
diskPersistent:是否缓存虚拟机重启期数据。
diskSpoolBufferSizeMB:这个参数设置 DiskStore(磁盘缓存)的缓存区大小。默认是 30MB。每个 Cache 都应该有自己的一个缓冲区。
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是 120 秒。
memoryStoreEvictionPolicy:当达到 maxElementsInMemory 限制时,Ehcache 将会根据指定的策略去清理内存。默认策略是 LRU(最近最少使用)。你可以设置为 FIFO(先进先出)或是 LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
memoryStoreEvictionPolicy:缓存策略,可选策略有:
FIFO(First In First Out),这个是大家最熟的,先进先出。
LFU(Less Frequently Used),就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
LRU(Least Recently Used),最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
在 SpringBoot 应用主类上添加 @EnableCaching
开启缓存支持,进行自动扫描。
@SpringBootApplication @EnableCaching public class EhcacheApplication { public static void main(String[] args) { SpringApplication.run(EhcacheApplication.class, args); } } 复制代码
模拟数据库数据
/** * 数据工厂,模拟数据库的数据 * * @author star **/ public class DataFactory { private DataFactory() { } private static List<UserDTO> userDtoList; static { // 初始化集合 userDtoList = new ArrayList<>(); UserDTO user = null; for (int i = 0; i < 5; i++) { user = new UserDTO(); user.setName("star" + i); user.setAge(23); userDtoList.add(user); } } public static List<UserDTO> getUserDaoList() { return userDtoList; } } 复制代码
/** * UserRepository * * @author star */ @Repository public class UserRepository { /** * 获取用户信息(此处是模拟的数据) */ public UserDTO getUserByName(String username) { UserDTO user = getUserFromList(username); return user; } /** * 从模拟的数据集合中筛选 username 的数据 */ private UserDTO getUserFromList(String username) { List<UserDTO> userDaoList = DataFactory.getUserDaoList(); for (UserDTO user : userDaoList) { if (Objects.equals(user.getName(), username)) { return user; } } return null; } } 复制代码
/** * UserService * * @author star **/ @Service @CacheConfig(cacheNames = "user") public class UserService { @Autowired private UserRepository userRepository; @Cacheable(key = "#name") public UserDTO getUser(String name) { UserDTO user = userRepository.getUserByName(name); return user; } } 复制代码
由于在上一篇springboot-cache 已经对缓存用法做了详细说明,这里就简单介绍一下:
@Cacheable
: 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存。同时在查询时,会先从缓存中获取,若不存在才再发起对数据库的访问。
@CachePut
:配置于方法上时,能够根据参数定义条件来进行缓存,其与 @Cacheable 不同的是,它不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中,所以主要用于数据新增和修改操作上。
@CacheEvict
:配置于方法上时,表示从缓存中移除相应数据。
编写 Controller 层
/** * UserResource * * @author star */ @RestController @RequestMapping("/api") public class UserResource { @Autowired private UserService userService; @GetMapping("/users/{name}") public ResponseEntity<UserDTO> getUser(@PathVariable("name") String name) { UserDTO user = userService.getUser(name); return ResponseEntity.ok(user); } } 复制代码
通过多次向接口 http://localhost:8080/api/users/star1
GET 数据来观察效果:
可以看到缓存的启用和效果如下所示: