springboot配置ehcache2.X缓存(@Cacheable等注解和手动操作缓存的工具类 支持element粒度的时间设置)

springboot配置ehcache2.X缓存(@Cacheable等注解和手动操作缓存的工具类 支持element粒度的时间设置)

本文只写出一些注意事项和源码,请善用官方文档~

注解实现

@Cacheable @CachePut @CacheEvit
启动类上加@EnableCaching就可以开启缓存
由文档可知,自动检测缓存实现的默认顺序为
1.Generic
2.JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and others)
3.EhCache 2.x
4.Hazelcast
5.Infinispan
6.Couchbase
7.Redis
8.Caffeine
9.Simple
默认是1,ConcurrentHashMap的实现
在classpath下放入ehcache.xml并在pom.xml中添加依赖就可以切换到EhCache 2.x
注意:net.sf.ehcache是2.X org.ehcache是3.X
spring.cache.cache-names不生效,需要在ehcache.xml中配置,注解使用了不存在的cacheName会报错
注解中key的值可以由el表达式拼接,例如

@Cacheable(value = "test", key = "#root.targetClass.name +'.'+#root.method.name+':'+#root.args[0]")

https://docs.spring.io/spring/docs/5.1.10.RELEASE/spring-framework-reference/integration.html#cache-spel-context

<?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">
    <defaultCache maxElementsInMemory="1000"
                  overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="3600"
                  timeToLiveSeconds="3600" memoryStoreEvictionPolicy="LRU"/>
    <!--
       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:内存数量最大时是否清除。
       -->
    <cache name="5s" maxElementsInMemory="100"
           overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="5" timeToLiveSeconds="5"
           memoryStoreEvictionPolicy="LRU"/>
</ehcache>

工具类CacheUtils

先看部分源码
springboot的CacheManager高层实现(各种缓存框架抽象出来的interface)
EhCacheCacheManager为ehcache的实现对象(仍是spring包下)
getCacheManager()可拿到EhCache低层实现的实例对象(ehcache包下)

Cache也是类似

import net.sf.ehcache.Cache;
import net.sf.ehcache.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.context.annotation.Configuration;

@Configuration
public class CacheUtils {
    private static CacheManager manager;

    @Autowired
    public void setManager(CacheManager manager) {
        CacheUtils.manager = manager;
    }

    public static Object get(String cacheName, Object key) {
        return cache(cacheName).get(key).getObjectValue();
    }

    public static void put(String cacheName, Object key, Object value, Integer ttl, Integer tti) {
        Element e = new Element(key, value);
        //不设置则使用xml配置
        if (ttl != null)
            e.setTimeToLive(ttl);
        if (tti != null)
            e.setTimeToIdle(tti);
        cache(cacheName).put(e);
    }

    public static boolean remove(String cacheName, Object key) {
        return cache(cacheName).remove(key);
    }

    public static void removeAll(String cacheName) {
        cache(cacheName).removeAll();
    }

    private static Cache cache(String cacheName) {
        net.sf.ehcache.CacheManager cacheManager = ((EhCacheCacheManager) manager).getCacheManager();
        if (!cacheManager.cacheExists(cacheName))
            cacheManager.addCache(cacheName);
        return cacheManager.getCache(cacheName);
    }
}


先判断是否存在对应cacheName的cache,避免空指针异常
timeToIdleSeconds和timeToLiveSeconds,有element级设置以其为准,没有以ehcache.xml为准