Ehcache配置详解与SpringBoot整合实例

Stella981
• 阅读 683

1. 配置

1.1 基本配置

下面基本算是使用Ehcache的xml最简配置了。

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="mycache-manager" updateCheck="false">
    <!-- 磁盘缓存位置 -->
    <diskStore path="java.io.tmpdir/ehcache"/>
    
    <!-- 默认缓存 -->
    <defaultCache
            maxEntriesLocalHeap="1000"
            eternal="false"
            timeToIdleSeconds="3600"
            timeToLiveSeconds="3600"
            overflowToDisk="false">
    </defaultCache>

    <!-- 用户缓存策略 -->
    <cache name="userCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="600"
           timeToLiveSeconds="0"
           overflowToDisk="false"
           statistics="true">
    </cache>
</ehcache>

1.2 ehcache

每个ehcache对应一个CacheManager,ehcache的name用来配置CacheManager的名称。

可以通过下面的方式获取:

CacheManager cacheManager = CacheManager.getCacheManager("mycache-manager");

1.3 diskStore

diskStore用来配置缓存数据保存的磁盘位置,常用的三个:

  1. user.home:用户主目录
  2. user.dir:用户当前工作目录
  3. java.io.tmpdir:默认临时文件路径

当然也可以使用绝对路径

1.4 defaultCache

默认缓存策略,当Ehcache没有找到缓存策略的时候,就会使用这个缓存策略,只能定义一个默认策略。

1.5 cache配置项

缓存策略,设置缓存超时时间,最大缓存数目等。

配置项

说明

name

缓存的名称,可以通过指定名称获取指定的某个Cache对象

eternal

true,永不过期,超时设置将被忽略,一些静态的配置数据可以设置为true

statistics

是否收集统计信息,如果需要监控缓存使用情况,应该设置为true,默认false,统计对性能有影响

clearOnFlush

内存数量最大时是否清除

overflowToDisk

内存不足时,是用磁盘进行缓存

diskPersistent

是否启用磁盘持久化的机制,JVM重启时可以加载之前缓存,默认值是false

timeToIdleSeconds

对象允许闲置时间,单位秒,超时过期,0表示可以一直空闲

timeToLiveSeconds

缓存数据最多存活时间,0表示不过期,timeToLiveSeconds不等于0时应该大于timeToIdleSeconds

maxElementsOnDisk

磁盘最大缓存多少cache数量

maxElementsInMemory

内存中允许存储的最大的元素个数,0代表无限个

maxEntriesLocalDisk

当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中

maxEntriesLocalHeap

堆内存中最大缓存对象数,0表示没有限制

diskSpoolBufferSizeMB

设置磁盘缓存的缓存区大小,默认是30MB,每个Cache都应该有自己的一个缓冲区

memoryStoreEvictionPolicy

缓存达到maxElementsInMemory限制时,内存缓存过期策略算法,LRU(最近最少使用,默认)、FIFO(先进先出)、LFU(最少访问次数)

diskExpiryThreadIntervalSeconds

检查磁盘缓存数据过期线程运行时间间隔,默认是120秒

1.6 通过编程式配置

@Test
public void createCache(){
    CacheManager cacheManager = CacheManager.create();
    Cache cache = new Cache("cacheName", 1000, true, false, 120, 120);
    CacheConfiguration config = cache.getCacheConfiguration();
    config.setClearOnFlush(true);
    config.setMaxEntriesLocalHeap(100);
    cacheManager.addCache(cache);
}

2. Spring与Ehcache

Spring对缓存的支持,是通过代理实现的,直接通过注解标就可以实现缓存,基本不需要处理太多和缓存相关的逻辑。

Spring的几个缓存相关的注解参数都支持SpEL表达式,下面是几个SpEL常用表达:

属性

位置

说明

示例

args

root

当前方法参数数组

#root.args[0]

method

root

当前方法

#root.method.name

target

root

当前被调用的对象

#root.target

caches

root

当前被调用的方法使用的Cache

#root.caches[0].name

methodName

root

当前方法名

#root.methodName

targetClass

root

当前被调用的对象的class

#root.targetClass

argument

context

当前被调用的参数,saveUser(User user)

#user.id

result

context

当前被调用的返回值

#result

2.1 @Cacheable

用@Cacheable注解的方法表示会缓存改方法的返回值。

当第一次调用这个方法时,方法的返回值会被缓存下来,在缓存的有效时间内,以后访问这个方法都直接返回缓存结果,不再执行方法中的代码段。

@Cacheable参数:

  1. value:缓存策略名称用于查找缓存位置,不能为空,Ehcache就是xml配置的cache的name,说明缓存数据放到哪个Cache中
  2. key:指定缓存使用的key,默认为空,既表示使用方法的参数类型及参数值作为key,支持SpEL
  3. condition:触发条件,只有满足条件的情况才会加入缓存,默认为空,既表示全部都加入缓存,支持SpEL

2.2 @CachePut

@CachePut和@Cacheable基本一样,但是它每次都会执行方法。一般用在更新方法上,这样可以同时更新缓存和数据库。

2.3 @CacheEvict

@CacheEvict用来删除缓存数据,它有参数:

  1. value:缓存策略名称用于查找缓存位置,不能为空
  2. key:缓存的key,默认为空
  3. condition:触发条件,只有满足条件的情况才会清除缓存,默认为空
  4. allEntries:是否清除全部缓存,默认为false,true表示清除value指定策略中的全部缓存

3. 实例与测试

3.1 maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

 <!--Spring Boot应用程序提供缓存支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<!--Ehcache缓存实现-->
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>
<!--JSR-107缓存规范-->
<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
</dependency>

依赖中忽略了spring-boot-starter-parent,选择自己喜欢的版本加入:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.1</version>
</parent>

3.2 spring 配置

logging.config=classpath:logback.xml

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/data?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=tim
spring.datasource.password=123456

spring.jpa.database=MySQL
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update

spring.datasource.hikari.maximum-pool-size=20 
spring.datasource.hikari.minimum-idle=5

spring.cache.jcache.config=classpath:ehcache.xml

3.3 Ehcache配置

<?xml version="1.0" encoding="UTF-8"?>
<ehcache name="mycache-manager" updateCheck="false">

    <!-- 缓存数据磁盘位置 -->
    <diskStore path="java.io.tmpdir"/>
    
    <!-- 默认缓存 -->
    <defaultCache
            maxEntriesLocalHeap="1000"
            eternal="false"
            timeToIdleSeconds="3600"
            timeToLiveSeconds="3600"
            overflowToDisk="false">
    </defaultCache>

    <!-- 用户缓存策略 -->
    <cache name="userCache"
           maxEntriesLocalHeap="2000"
           eternal="false"
           timeToIdleSeconds="60"
           timeToLiveSeconds="120"
           overflowToDisk="false"
           diskPersistent="true">
    </cache>
</ehcache>

将diskPersistent设置为true,方便执行不同Test的时候,还保留之前的缓存。

这里使用的是Ehcache的2.x版本,3.x版本做了很多的变化,实现了JSR-107,如果可以尽量选择3.x的版本。

Ehcache配置类:

@Configuration
@EnableCaching
public class EhcacheConfiguration {

    @Bean(name = "ehCacheCacheManager")
    public EhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean bean){
        return new EhCacheCacheManager(bean.getObject());
    }

    @Bean
    public EhCacheManagerFactoryBean ehCacheManagerFactoryBean(){
        EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean();
        ClassPathResource classPathResource = new ClassPathResource("ehcache.xml");
        cacheManagerFactoryBean.setConfigLocation (classPathResource);
        cacheManagerFactoryBean.setShared(true);
        return cacheManagerFactoryBean;
    }
}

使用@EnableCaching注解开启Spring缓存。

3.4 启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories(basePackages = {"vip.mycollege.jpa.mysql.repository"})
public class Start {
    public static void main(String[] args) {
        SpringApplication.run(Start.class, args);
    }
}

3.5 实体类

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;

@Entity
@Table(name = "user")
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer id;
    private Integer age;
    @Column(length = 20)
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

实体类要实现Serializable,Ehcache持久化对象到磁盘需要。

3.6 Repository

import org.springframework.data.repository.CrudRepository;
import vip.mycollege.jpa.mysql.entity.User;

public interface UserRepository extends CrudRepository<User,Integer> {

}

3.7 缓存逻辑

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import vip.mycollege.jpa.mysql.entity.User;
import vip.mycollege.jpa.mysql.repository.UserRepository;

import javax.annotation.Resource;

@Service
public class EhcacheService {

    @Resource
    private UserRepository userRepository;

    @Cacheable(value="userCache", key="'user:' + #id")
    public User findUserById(Integer id) {
        System.out.println("execute findUserById");
        return userRepository.findById(id).get();
    }

    @Cacheable(value="userCache", condition="#id < 3")
    public User findCacheConditionUserById(Integer id) {
        System.out.println("execute findCacheConditionUserById");
        return userRepository.findById(id).get();
    }

    @CacheEvict(value="userCache",key="'user:' + #user.id")
    public void deleteUser(User user) {
        System.out.println("execute deleteUser");
        userRepository.deleteById(user.getId());
    }

    @CacheEvict(value="userCache", allEntries=true)
    public void deleteAllUserCache() {
        System.out.println("execute deleteAllUserCache");
        System.out.println("delete all cache");
    }

    @CachePut(value = "userCache",key = "'user:'+#user.id")
    public User updateUser(User user) {
        System.out.println("execute updateUser");
        user.setAge(100);
        userRepository.save(user);
        return user;
    }
}

可以自己生成一些数据,然后用下面的测试类来测试不同缓存的效果。

3.8 测试类

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import vip.mycollege.jpa.mysql.entity.User;

import javax.annotation.Resource;


@RunWith(SpringRunner.class)
@SpringBootTest
public class EhcacheServiceTest {

    @Resource
    private EhcacheService ehcacheService;

    @Test
    public void findUserById() {
        User user = ehcacheService.findUserById(1);
        System.out.println(user);
    }

    @Test
    public void findCacheConditionUserById() {
        User user = ehcacheService.findCacheConditionUserById(5);
        System.out.println(user);
    }

    @Test
    public void deleteUser() {
        User user = new User();
        user.setId(1);
        ehcacheService.deleteUser(user);
    }

    @Test
    public void deleteAllUserCache() {
        ehcacheService.deleteAllUserCache();
    }

    @Test
    public void updateUser() {
        User user = new User();
        user.setId(1);
        ehcacheService.updateUser(user);
    }
}

4. 文档资料

Ehcache2.9文档 Ehcache3.8文档 Ehcache快速开始 Ehcache示例 SpringBoot缓存文档

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这