SpringBoot 整合 Ehcache 2.x 缓存

整合步骤如下:

  1. 添加依赖

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-cacheartifactId>
dependency>


<dependency>
    <groupId>net.sf.ehcachegroupId>
    <artifactId>ehcacheartifactId>
dependency>
  1. 添加缓存配置文件

    如果 Ehcache 的依赖存在并且在 classpath 下有一个名为 ehcache.xmlEhcache 配置文件, 那么 EhCacheCacheManager 将会自动作为缓存的实现。因此,在 resources 目录下创建 ehcache.xml 文件作为 Ehcache 缓存的配置文件,代码如下:

<ehcache>
    <diskStore path="java.io.tmpdir/cache" />
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120" />
    <cache name="book_cache"
           maxElementsInMemory="10000"
           eternal="true"
           timeToIdleSeconds="120"
           timeToLiveSeconds="120"
           overflowToDisk="true"
           diskPersistent="true"
           diskExpiryThreadIntervalSeconds="600" />
ehcache>
  • 配置文件中提供了两个缓存策略,一个是默认的,另一个名为 book_cache 。其中 name 表示缓存名称。
  • maxElementsInMemory 表示缓存最大个数。
  • eternal 表示缓存对象是否永久有效,一旦设置了永久有效,timeout 将不起作用。
  • timeToIdleSeconds 表示缓存对象在失效前的允许闲置时间(单位:秒),当 etemal = false 对象不是永久有效时,该属性才生效。
  • timeToLiveSeconds 表示缓存对象在失效前允许存活的时间(单位:秒),在 etemal = false 对象不是 永久有效时,该属性才生效。
  • overflowToDisk 表示当内存中的对象数量达到 maxElementsInMemory 时,Ehcache 是否将对象写到磁盘中。
  • diskExpiryThreadIntervalSeconds 表示磁盘失效线程运行时间间隔。
  • 若想自定义 Ehcache 配置文件的名称和位置,可以在 application.properties 中添加如下配置 :
spring.cache.ehcache.config=classpath:config/another-config.xml 
  1. 在项目的入口类上添加 @EnableCaching 注解开启缓存,代码如下:
@SpringBootApplication
@EnableCaching
public class BootApplication {
    public static void main(String[] args) {
        SpringApplication.run(BootApplication.class, args);
    }
}
  1. 创建 Book 实体类和 BookCacheDAO 类,代码如下:
import java.io.Serializable;
import java.util.Date;

public class Book implements Serializable {
    private Integer bookId;
    private String name;
    private String author;
    private Float price;
    private Date publicationDate;

	// 省略 getter/setter
    @Override
    public String toString() {
        return "Book { bookId: " + bookId + "; name: " + name + "; author: " + author
                + "; price: " + price + "; publicationDate: " + publicationDate + "}";
    }
}
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
import xyz.ther.boot.pojo.Book;

@Repository
@CacheConfig(cacheNames = "book_cache")
public class BookCacheDAO {

    @Cacheable
    public Book getBookById(Integer id) {
        System.out.println("getBookById");
        Book book = new Book();
        book.setBookId(id);
        book.setName("Cache 书");
        book.setAuthor("Cache 作者");
        return book;
    }

    @CachePut(key = "#book.bookId")
    public Book updateBook(Book book) {
        System.out.println("updateBook");
        book.setName("Cache 书(第二版)");
        return book;
    }

    @CacheEvict(key = "#bookId")
    public void deleteBookById(Integer bookId) {
        System.out.println("deleteBookById");
    }
}
  • BookCacheDao 上添加 @CacheConfig 注解指明使用的缓存的名字,这个配置可选,若不使用 @CacheConfig 注解,则直接在 @Cacheable 注解中指明缓存名字。

  • getBookByld 方法上添加 @Cacheable 注解表示对该方法进行缓存,默认情况,缓存的 key 是方法的参数,缓存的 value 是方法的返回值。当开发者在其他类中调用该方法时,首先会根据调用参数查看缓存中是否有相关数据,若有,则直接使用缓存数据,该方法不会执行,否则执行该方法,执行成功后将返回值缓存起来,但若是在当前类中调用该方法,则缓存不会生效。

  • @Cacheable 注解中还有一个属性 condition 用来描述缓存的执行时机,例如 @Cacheable(condition ="#id%2==0")表示当 id 取模为 0 时才进行缓存,否则不缓存。

  • 若不想使用默认的 key,也可以自定义 key 。像示例中一样,updateBook 方法示例表示存的 key 为参数 book 对象的 bookId 的值,deleteBookById 方法表示缓存的 key 为参数 bookId

  • @CachePut 注解一般用于数据更新方法上,与 @Cacheable 注解不同,添加了 @CachePut 注解的方法每次在执行时都不去检查缓存中是否有数据,而是直接执行方法,然后将方法的执行结果缓存起来,如果该 key 对应的数据已经被缓存起来了,那么就会覆盖之前的数据,这样可以避免再次加载数据时获取到脏数据。同时,@CachePut 具有和 @Cacheable 相似的属性。

  • @CacheEvict 注解一般用于删除方法上,表示移除一个 key 对应的缓存。@CacheEvict 注解有两个特殊的属性: allEntriesbeforelnvocation ,其中 allEntries 表示是否将所有的缓存数据都移除, 默认为 falsebeforelnvocation 表示是否在方法执行之前移除缓存中的数据,默认为 false ,即在方法执行之后移除缓存中的数据。

  1. 创建测试类
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
import xyz.ther.boot.pojo.Book;

@Repository
@CacheConfig(cacheNames = "book_cache")
public class BookCacheDAO {

    @Cacheable
    public Book getBookById(Integer id) {
        System.out.println("getBookById");
        Book book = new Book();
        book.setBookId(id);
        book.setName("Cache 书");
        book.setAuthor("Cache 作者");
        return book;
    }

    @CachePut(key = "#book.bookId")
    public Book updateBook(Book book) {
        System.out.println("updateBook");
        book.setName("Cache 书(第二版)");
        return book;
    }

    @CacheEvict(key = "#bookId")
    public void deleteBookById(Integer bookId) {
        System.out.println("deleteBookById");
    }
}

测试结果:

getBookById
deleteBookById
getBookById
Book { bookId: 1; name: Cache 书; author: Cache 作者; price: null; publicationDate: null}
updateBook
Book { bookId: 1; name: Cache 书(第二版); author: Cache Test 作者; price: null; publicationDate: null}

结果分析:

  • 执行了两个查询,但是查询方法只打印了一次,因为第二次使用了缓存。
  • 执行删除方法,之后再次执行查询,查询方法又被执行了,因为在删除方法中缓存己经被删除了 。
  • 再执行更新方法,更新方法中不仅更新数据,也更新了缓存,所以在最后的查询方法中,方法日志没打印,说明该方法没执行,而是使用了缓存中的数据,而缓存中的数据已经被更新了。

你可能感兴趣的:(SpringBoot)