spring boot & Ehcache

一、简介

缓存工作的原则,就是“引用的局部性”,这可以分为时间局部性和空间局部性。空间局部性是指CPU在某一时刻需要某个数据,那么很可能下一步就需要其附近的数据;时间局部性是指当某个数据被访问过一次之后,过不了多久时间就会被再一次访问。

常用缓存算法:

1.LRU算法
LRU(The Least Recently Used,最近最久未使用算法)是一种常见的缓存算法,如果一个数据在最近一段时间没有被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最久没有访问的数据最先被置换(淘汰)。

2.LFU算法
LFU(Least Frequently Used ,最近最少使用算法)也是一种常见的缓存算法。
如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能性也很小。因此,当空间满时,最小频率访问的数据最先被淘汰。

3.FIFO算法
FIFO 算法是一种比较容易实现的算法。思想是先进先出(FIFO,队列),这是最简单、最公平的一种思想,即如果一个数据是最先进入的,那么可以认为在将来它被访问的可能性很小。空间满的时候,最先进入的数据会被最早置换(淘汰)掉。

二、Ehcache

Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。

Ehcache 直接在jvm虚拟机中缓存,速度快,效率高;缓存数据有两级:内存和磁盘,因此无需担心容量问题但是缓存共享麻烦,集群分布式应用不方便。处理集群和分布式缓存方便,有成熟的方案。如果是单个应用或者对缓存访问要求很高的应用,用ehcache。如果是大型系统,存在缓存共享、分布式部署、缓存内容很大的,建议用redis。

三、流程

spring 已将缓存领域统一,无论使用哪种缓存实现,不同的只是缓存配置,开发者使用的缓存注解都是一致的。

spring boot 可以非常方便使用ehcache,如果ehcache 依赖存在,并且classpath 下有一个ehcache.xml 配置,EhCacheManager 将自动作为缓存实现。

1.新建spring boot 项目,pom.xml 添加依赖

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

<dependency>
	<groupId>net.sf.ehcache</groupId>
	<artifactId>ehcache</artifactId>
</dependency>

2.resources 下新建ehcache.xml

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
 
  <!-- 磁盘缓存位置 -->
  <diskStore path="./ehcache"/>
 
  <!-- 默认缓存 -->
  <defaultCache
          maxEntriesLocalHeap="100"
          eternal="false"
          timeToIdleSeconds="120"
          timeToLiveSeconds="120"
          diskExpiryThreadIntervalSeconds="120">
          
  </defaultCache>
  
  <!-- 配置一个default_cache  的缓存 -->
  <cache name="default_cache" 
   		  maxEntriesLocalHeap="100"
          eternal="false"
          timeToIdleSeconds="120"
          timeToLiveSeconds="120"
          diskExpiryThreadIntervalSeconds="120">
  </cache>
  
         
</ehcache>

3.@SpringBootApplication 修饰的启动类添加 @EnableCaching 注解开启缓存配置

4.User.java

package com.vincent.po;

import java.io.Serializable;

public class User implements Serializable {
	private static final long serialVersionUID = 1L;
	
	private String name;
	private int age;

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

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

	@Override
	public String toString() {
		return "User [name=" + name + ", age=" + age + "]";
	}

}

5.UserService.java

package com.vincent.service;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.vincent.po.User;

@Service
public class UserService {
	@Cacheable(cacheNames = {"default_cache"},key = "#id")
	public User get(String id) {
		User user = new User();
		user.setName("Vincent");
		user.setAge(26);
		System.out.println("cache method...");
		return user;
	}
	
	@CachePut(cacheNames = {"default_cache"},key = "#id")
	public User update(String id){
		
		User user = new User();
		user.setName("Vincent-" + id);
		user.setAge(26);
		System.out.println("update method...");
		return user;
	}
	
	@CacheEvict(cacheNames = {"default_cache"},key = "#id")
	public void delete(String id) {
		System.out.println("delete method...");
	}
}

@Cacheable 表示对方法进行缓存,默认情况下缓存的key 是方法的参数,缓存的value 是方法的返回值,其他类中调用该方法时,首先会根据调用参数查看缓存中是否有相关数据,如有则直接使用缓存数据,该方法不会执行,否则执行该方法并把返回值缓存起来

@CachePut 用于数据更新方法上,每次执行时都不会检查是否已有数据,而是直接执行方法,让后将执行结果缓存起来,如果该key对应的数据已经存在将会被覆盖

@CacheEvice 表示移除一个key 对应的缓存

6.TestController.java

package com.vincent.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import com.vincent.po.User;
import com.vincent.service.UserService;

@RestController
public class TestController {
	
	@Autowired 
	private UserService userService;
	
	@GetMapping("/test/add")
	public User add(String id) {
		return userService.get(id);
	}
	
	@GetMapping("/test/update")
	public User update(String id) {
		return userService.update(id);
	}

	
	@GetMapping("/test/del")
	public void del(String id) {
		userService.delete(id);
	}
	
}

四、测试

1.访问 http://localhost:8080/test/add?id=test-cache

浏览器输出:
在这里插入图片描述

控制台输出:
在这里插入图片描述
多次刷新该接口控制台输出没有多余的 cache method… ,表面数据缓存成功

2.访问 http://localhost:8080/test/update?id=test-cache 更新数据
在这里插入图片描述

控制台输出如下:
在这里插入图片描述

再次刷新该接口控制台将再次执行该更新方法

在这里插入图片描述

3.访问 http://localhost:8080/test/del?id=test-cache

浏览器没有任何信息
在这里插入图片描述

控制台输出 delete method…

4.再次访问 http://localhost:8080/test/add?id=test-cache 缓存方法将被执行。
控制台输出 cache method…

五、总结

ehcache.xml 配置文件中需要配置缓存名字如:

<cache name="xxx" />

代码中对缓存的注解中需要指定 cacheNames 缓存名称,否制会抛异常,
在这里插入图片描述
查找相关异常代码如下
在这里插入图片描述
在使用ehcache 时需要指定缓存名字,否制会抛异常。ehcache.xml 配置中的defaultCache 就没什么作用,cache 配置的参数和 defaultCache 一样,不过多了一个name 属性。defaultCache 可能时给用户参考配置使用的。

cache 配置参数说明如下:

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

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

clearOnFlush:内存数量最大时是否清除。

eternal :设置缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。根据存储数据的不同,例如一些静态不变的数据如省市区等可以设置为永不过时

timeToIdleSeconds : 设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。

timeToLiveSeconds :缓存数据的生存时间(TTL),也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0就意味着元素可以停顿无穷长的时间。

overflowToDisk :内存不足时,是否启用磁盘缓存。

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

maxElementsOnDisk:硬盘最大缓存个数。

diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。

diskPersistent:是否在VM重启时存储硬盘的缓存数据。默认值是false。

diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。

maxEntriesLocalHeap:是用来限制当前缓存在堆内存上所能保存的最大元素数量的。Ehcache规定如果在CacheManager上没有指定maxBytesLocalHeap时必须在各个Cache上指定maxBytesLocalHeap或者maxEntriesLocalHeap,但maxEntriesLocalHeap和maxBytesLocalHeap不能同时出现。也就是说我们不能在一个Cache上同时指定maxBytesLocalHeap和maxEntriesLocalHeap,也不能在Cache上指定maxEntriesLocalHeap的同时在CacheManager上指定maxBytesLocalHeap。但同时在CacheManager和Cache上指定maxBytesLocalHeap则是允许的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值