天天看點

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緩存文檔