springboot2集成ehcache3

POM.XML增加依赖

<!-- springboot EhCache3 -->
<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
</dependency>
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>3.7.1</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

配置文件,放在resource根目录下

<?xml version="1.0" encoding="UTF-8" ?>
<eh:config
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:eh='http://www.ehcache.org/v3'
xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core-3.3.xsd">
    <!--指定缓存目录 -->
    <eh:persistence directory="${java.io.tmpdir}/cache-data" />
    
    <!--缓存模板 -->
    <eh:cache-template name="default">
        <eh:expiry>
            <eh:ttl unit="seconds">600</eh:ttl>
        </eh:expiry>
        <eh:resources>
            <!--堆内内存可以放2000个条目,超出部分堆外100MB -->
            <eh:heap unit="entries">2000</eh:heap>
            <eh:offheap unit="MB">10</eh:offheap>
        </eh:resources>
    </eh:cache-template>
    <!--实际的缓存区间,继承了default缓存模板,sample完全使用模板默认 -->
    <!-- <eh:cache alias="sample" uses-template="default"></eh:cache> -->
    <!--下面两个继承了default缓存模板,但覆盖了缓存的过期时间 -->
    <!-- <eh:cache alias="authority_service" uses-template="default">
    <eh:expiry>
    <eh:ttl unit="hours">1</eh:ttl>
    </eh:expiry>
    </eh:cache> -->
    <eh:cache alias="article_detail" uses-template="default">
        <eh:expiry>
            <eh:ttl unit="hours">12</eh:ttl>
        </eh:expiry>
    </eh:cache>
    <eh:cache alias="article_list" uses-template="default">
        <eh:expiry>
            <eh:ttl unit="hours">24</eh:ttl>
        </eh:expiry>
    </eh:cache>
</eh:config>

application.properties配置

# 可选,配置了spring.cache.jcache.config属性会自动装配JCacheCacheManager
spring.cache.type=jcache
# 指定ehcache的配置文件所在的位置
spring.cache.jcache.config=classpath:ehcache-3.x.xml

key值生成

根据类名、方法名、参数信息自动生成key和匹配

CustomKeyGenerator.java

package com.daimeng.ehcache;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Configuration;
import com.alibaba.fastjson.JSONObject;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Arrays;
@Configuration
public class CustomKeyGenerator implements KeyGenerator {
@Override
    public Object generate(Object target, Method method, Object... params) {
        return new CustomKey(target.getClass(), method.getName(), params);
    }
    /**
     * Like {@link org.springframework.cache.interceptor.SimpleKey} but considers the method.
     */
    static final class CustomKey implements Serializable{
    private static final long serialVersionUID = 1L;
    
        private final Class<?> clazz;
        private final String methodName;
        private final Object[] params;
        private final int hashCode;
        /**
         * Initialize a key.
         *
         * @param clazz the receiver class
         * @param methodName the method name
         * @param params the method parameters
         */
        CustomKey(Class<?> clazz, String methodName, Object[] params) {
            this.clazz = clazz;
            this.methodName = methodName;
            this.params = params;
            //int code = Arrays.deepHashCode(params);
            int code = Arrays.deepHashCode(getStringCode(params));
            code = 31 * code + clazz.hashCode();
            code = 31 * code + methodName.hashCode();
            this.hashCode = code;
        }
        @Override
        public int hashCode() {
            return this.hashCode;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }
            if (!(obj instanceof CustomKey)) {
                return false;
            }
            CustomKey other = (CustomKey) obj;
            if (this.hashCode != other.hashCode) {
                return false;
            }
            return this.clazz.equals(other.clazz)
                    && this.methodName.equals(other.methodName)
                    && Arrays.deepEquals(getStringCode(this.params), getStringCode(other.params));
            //&& Arrays.deepEquals(this.params, other.params)
        }
        
        public String[] getStringCode(Object[] params) {
        String[] s = new String[params.length];
        for(int i = 0; i < params.length; i ++) {
        String json = JSONObject.toJSONString(params[i]);
        s[i] = json;
        }
        return s;
        }
    }
}

CustomCachingConfig

package com.daimeng.ehcache;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CustomCachingConfig extends CachingConfigurerSupport {
 @Override
    public KeyGenerator keyGenerator() {
        return new CustomKeyGenerator();
    }
}


service增加注解

/**
*
* @功能描述: TODO
*   @Cacheable Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,
*         如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中
*     @CachePut 标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中
*     @CacheEvict 是用来标注在需要清除缓存元素的方法或类上的
*         可以指定的属性有value、key、condition、allEntries和beforeInvocation
*         allEntries:是boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。
*         当指定了allEntries为true时,Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素,这比一个一个清除元素更有效率
*         beforeInvocation:清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。
*         使用beforeInvocation可以改变触发清除操作的时间,当我们指定该属性值为true时,Spring会在调用该方法之前清除缓存中的指定元素
* @名称: ArticleServiceImpl.java
* @路径 com.daimeng.web.article.service.impl
* @作者 daimeng.fun
* @E-Mail sephy9527@qq.com
* @创建时间 2020年8月29日 上午12:19:15
* @version V1.0
*/
@Service
@EnableCaching
public class ArticleServiceImpl implements ArticleService{
    ......
    
    //value:使用叫做'shop_service'的缓存器
        //key: 缓存的key等于#type,即传入的key值
        //condition:缓存的条件,当#type等于phone时,才进行缓存
        //@Cacheable(cacheNames = "shop_service", key = "#typeId", condition = "#type == 'phone'")
    @Override
    @Cacheable(value = "article_detail", key = "#id")
    public ArticleInfo findArticleInfoById(Integer id) {
        .....
    }
    
    @Override
    @Cacheable(value = "article_list")
    public Page<ArticleInfo> findAllBySpecification(final ArticleInfo info, int page) {
        .....
    }
    
    @Override
    @Caching(evict= {
            @CacheEvict(value = "article_list", allEntries = true),
            @CacheEvict(value = "article_detail", key = "#info.id")
    })
    public ArticleInfo addArticle(ArticleInfo info) {
        .....
    }
    @Override
    @Caching(evict= {
            @CacheEvict(value = "article_list", allEntries = true),
            @CacheEvict(value = "article_detail", key = "#info.id")
    })
    public ArticleInfo updateArticle(ArticleInfo info) {
        .....
        
    }
    @Override
    @CacheEvict(value = "article_list", allEntries = true)
    public ArticleInfo deleteArticle(ArticleInfo info) {
        .....
        
    }
   

}



{context}