Spring Boot 之 Ehcache 2.x缓存

Ehcache 2.x缓存

Ehcache缓存在Java开发领域已是久负盛名,在Spring Boot中,只需要一个配置文件就可以将Ehcache集成到项目中。Ehcache 2.x的使用步骤如下。

1. 创建项目,添加缓存依赖,

创建Spring Boot项目,添加spring-boot-starter-cache依赖以及Ehcache依赖,代码如下:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

2. 添加缓存配置文件

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

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
       user.home – 用户主目录
       user.dir  – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
     -->
    <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
    <!--
       defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
     -->
    <!--
      name:缓存名称。
      maxElementsInMemory:缓存最大数目
      maxElementsOnDisk:硬盘最大缓存个数。
      eternal:对象是否永久有效,一但设置了,timeout将不起作用。
      overflowToDisk:是否保存到磁盘,当系统当机时
      timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
      timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
      diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
      diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
      memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
      clearOnFlush:内存数量最大时是否清除。
      memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
      FIFO,first in first out,这个是大家最熟的,先进先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
   -->
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="book_cache"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>

</ehcache>

这是一个常规的Ehcache 配置文件,提供了两个缓存策略,一个是默认的,另一个名为book_cache。 其中,name表示缓存名称; maxElementsInMemory 表示缓存最大个数; eternal 表示缓存对象是否永久有效,一旦设置了 永久有效,timeout 将不起作用; timeToIdleSeconds 表示缓存对象在失效前的允许闲置时间(单位:秒),当eternal=false对象不是永久有效时,该属性才生效;timeToLiveSeconds表示缓存对象在失效前允许存活的时间(单位:秒),当eternal=false对象不是永久有效时,该属性才生效; overflowToDisk 表示当内存中的对象数量达到maxElementsInMemory时,Ehcache 是否将对象写到磁盘中; diskExpiryThreadIntervalSeconds 表示磁盘失效线程运行时间间隔。还有其他更为详细的Ehcache配置,这里就不一-介绍了。另外,如果开发者想自定义Ehcache。配置文件的名称和位置,可以在application.properties中添加如下配置:

spring.cache.ehcache.config=classpath:config/anothor-config.xml

3. 开启缓存

在项目的入口类上添加@EnableCaching注解开启缓存,代码如下:

@SpringBootApplication
@EnableCaching
public class SpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestspringbootApplication.class, args);
    }
}

4. 创建BookDao

创建Book实体类和BookService,代码如下:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book implements Serializable {
    private Integer id;
    private String name;
    private String author;
}
@Repository
@CacheConfig(cacheNames = "book_cache")
public class BookDao {
    @Cacheable
    public Book getBookById(Integer id) {
        System.out.println("getBookById");
        Book book = new Book();
        book.setId(id);
        book.setAuthor("罗贯中");
        book.setName("三国演义");
        return book;
    }
    @CachePut(key = "#book.id")
    public Book updateBookById(Book book){
        System.out.println("updateBookById");
        book.setName("三国演义2");
        return book;
    }
    @CacheEvict(key = "#id")
    public void deleteBookById(Integer id){
        System.out.println("deleteBookById");
    }
}

代码解释:

  • 在BookDao. 上添加@CacheConfig 注解指明使用的缓存的名字,这个配置可选,若不使用@CacheConfig注解,则直接在@Cacheable注解中指明缓存名字。
  • 第4 行在getBookById方法.上添加@Cacheable注解表示对该方法进行缓存,默认情况下,缓存的key是方法的参数,缓存的value是方法的返回值。当开发者在其他类中调用该方法时,首先会根据调用参数查看缓存中是否有相关数据,若有,则直接使用缓存数据,该方法不会执行,否则执行该方法,执行成功后将返回值缓存起来,但若是在当前类中调用该方法,则缓存不会生效。
  • @Cacheable注解中还有一个属性condition用来描述缓存的执行时机,例如.@Cacheable(condition = “#id%2==0”)表示当 id对2取模为0时才进行缓存,否则不缓存。
  • 如果开发者不想使用默认的key, 也可以像第13行和第19行一样自定义key, 第13行表示缓存的key为参数book对象中id的值,第19行表示缓存的key为参数id。除了这种使用参数定义key的方式之外,Spring 还提供了一个root对象用来生成key,如表所示。

使用root对象生成key

属性名称属性描述用法示例
methodName当前方法名#root.methodName
method当前方法对象#root.method.name
caches当前方法使用的缓存#root.cache[0].name
target当前被调用的对象#root.target
targetClass当前被调用的对象的Class#root.targetClass
args当前方法参数数组#root.args[0]
  • 如果这些key不能够满足开发需求,开发者也可以自定义缓存key的生成器KeyGenerator,代码如下:
@Component
public class MyKeyGenerator implements KeyGenerator {
    @Override
    public Object generate(Object target, Method method, Object... params) {
        return Arrays.toString(params);
    }
}
@Repository
@CacheConfig(cacheNames = "book_cache")
public class BookDao {
    @Autowired
    MyKeyGenerator myKeyGenerator;
    @Cacheable(keyGenerator = "myKeyGenerator")
    public Book getBookById(Integer id) {
        System.out.println("getBookById");
        Book book = new Book();
        book.setId(id);
        book.setAuthor("罗贯中");
        book.setName("三国演义");
        return book;
    }
}
  • 自定义MyKeyGenerator实现KeyGenerator接口,然后实现该接口中的generate方法,该方法的三个参数分别是当前对象、当前请求的方法以及方法的参数,开发者可根据这些信息组成一个新的key 返回,返回值就是缓存的key。 第5行在@Cacheable注解中引用MyKeyGenerator实例即可。
  • 第13行@CachePut注解一般用于数据更新方法上,与@Cacheable注解不同,添加了@CachePut注解的方法每次在执行时都不去检查缓存中是否有数据,而是直接执行方法,然后将方法的执行结果缓存起来,如果该key对应的数据已经被缓存起来了,就会覆盖之前的数据,这样可以避免再次加载数据时获取到脏数据。同时,@CachePut 具有和@Cacheable类似的属性,这里不再赘述。
  • 第19行@CacheEvict注解一般用于删除方法上,表示移除一个key对应的缓存。@CacheEvict注解有两个特殊的属性: allEntries 和beforeInvocation,其中allEntries 表示是否将所有的缓存数据都移除,默认为false, beforeInvocation 表示是否在方法执行之前移除缓存中的数据,默认为false,即在方法执行之后移除缓存中的数据。

5. 创建测试类

创建测试类,对Service中的方法进行测试,代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestspringbootApplication.class)
public class CachesApplicationTests {
    @Resource
    BookDao bookDao;

    @Test
    public void contextLoads() {
        bookDao.getBookById(1);
        bookDao.getBookById(1);
        bookDao.deleteBookById(1);
        Book bookById = bookDao.getBookById(1);
        System.out.println(bookById);
        Book book = new Book();
        book.setName("张三日记");
        book.setAuthor("罗翔");
        book.setId(1);
        bookDao.updateBookById(book);
        Book book1 = bookDao.getBookById(1);
        System.out.println(book1);
    }
}

执行该方法,控制台打印日志如图所示。

getBookById
deleteBookById
getBookById
Book(id=1, name=三国演义, author=罗贯中)
updateBookById
Book(id=1, name=三国演义2, author=罗翔)

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值