天天看点

Ehcache配置详解与SpringBoot整合实例

文章目录

    • 1. 配置
      • 1.1 基本配置
      • 1.2 ehcache
      • 1.3 diskStore
      • 1.4 defaultCache
      • 1.5 cache配置项
      • 1.6 通过编程式配置
    • 2. Spring与Ehcache
      • 2.1 @Cacheable
      • 2.2 @CachePut
      • 2.3 @CacheEvict
    • 3. 实例与测试
      • 3.1 maven依赖
      • 3.2 spring 配置
      • 3.3 Ehcache配置
      • 3.4 启动类
      • 3.5 实体类
      • 3.6 Repository
      • 3.7 缓存逻辑
      • 3.8 测试类
    • 4. 文档资料

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的名称。

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

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缓存文档