Ehcache
Ehcache is an open source, standards-based cache that boosts performance, offloads your database, and simplifies scalability. It’s the most widely-used Java-based cache because it’s robust, proven, full-featured, and integrates with other popular libraries and frameworks.
Quick Start
提供一个最简单的入门案例。
完整代码地址:cache-ehcache-hw
- pom.xml
引入 jar
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.4.0</version>
</dependency>
- HelloWorld.java
import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
public class HelloWorld {
public static void main(String[] args) {
CacheManager cacheManager
= CacheManagerBuilder.newCacheManagerBuilder()
.withCache("preConfigured",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)))
.build();
cacheManager.init();
Cache<Long, String> preConfigured =
cacheManager.getCache("preConfigured", Long.class, String.class);
Cache<Long, String> myCache = cacheManager.createCache("myCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(Long.class, String.class, ResourcePoolsBuilder.heap(10)).build());
myCache.put(1L, "da one!");
String value = myCache.get(1L);
System.out.println(value);
preConfigured.put(1L, "preConfigured data");
String valueTwo = preConfigured.get(1L);
System.out.println(valueTwo);
System.out.println(myCache.get(1L));
cacheManager.removeCache("preConfigured");
cacheManager.close();
}
}
运行结果:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
da one!
preConfigured data
da one!
Process finished with exit code 0
spring 整合
简单的和 spring 进行整合的例子。
完整代码地址:EhcacheTest.java
- 项目结构
├── cache-encache-spring.iml
├── pom.xml
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ └── ryo
│ │ │ └── cache
│ │ │ └── ehcache
│ │ │ └── spring
│ │ │ ├── model
│ │ │ │ └── User.java
│ │ │ └── service
│ │ │ ├── UserService.java
│ │ │ └── impl
│ │ │ └── UserServiceImpl.java
│ │ └── resources
│ │ ├── applicationContext-cache.xml
│ │ └── ehcache.xml
│ └── test
│ └── java
│ └── com
│ └── ryo
│ └── cache
│ └── ehcache
│ └── spring
│ ├── EhcacheTest.java
│ └── service
│ └── UserServiceTest.java
- pom.xml
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--cache-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.4</version>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
- applicationContext-cache.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 注解扫描路径 -->
<context:component-scan base-package="com.ryo.cache.ehcache.spring"/>
<!-- 支持缓存注解 -->
<cache:annotation-driven cache-manager="cacheManager"/>
<!-- 默认是cacheManager -->
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
<property name="cacheManager" ref="cacheManagerFactory"/>
</bean>
<!-- cache管理器配置 -->
<bean id="cacheManagerFactory" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation" value="classpath:ehcache.xml"/>
<property name="shared" value="true"/>
</bean>
</beans>
- ehcache.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<!--timeToIdleSeconds 当缓存闲置n秒后销毁 -->
<!--timeToLiveSeconds 当缓存存活n秒后销毁 -->
<!--
缓存配置
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<!-- 磁盘缓存位置 -->
<diskStore path="java.io.tmpdir/easylink-mall-web/ehcache"/>
<!-- 默认缓存 -->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<persistence strategy="localTempSwap"/>
</defaultCache>
<!-- 用户信息数据缓存 数据缓存40分钟 -->
<cache
name="user-apply-cache"
eternal="false"
timeToIdleSeconds="2400"
timeToLiveSeconds="2400"
maxEntriesLocalHeap="10000"
maxEntriesLocalDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
overflowToDisk="false"
memoryStoreEvictionPolicy="LRU">
</cache>
<!-- 自定义缓存,名称为 annotation.cache-->
<cache name="annotation.cache" maxElementsInMemory="50" eternal="false"
overflowToDisk="false" memoryStoreEvictionPolicy="LFU" />
</ehcache>
- EhcacheTest.java
import com.ryo.cache.ehcache.spring.model.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext-cache.xml")
public class EhcacheTest {
@Autowired
private CacheManager cacheManager;
@Test
public void execute() {
// 获取用户信息缓存容器
Cache cache = cacheManager.getCache("user-apply-cache");
Long id = 1L;
User user = new User(id, "缓存测试");
// 将用户信息数据添加至缓存中 // key : id value : object
cache.put(1L, user);
// 获取用户信息数据
// 方法1
User cacheUser1 = (User) cache.get(id).get();
System.out.println(cacheUser1.getName());
// 方法2
User cacheUser2 = cache.get(id, User.class);
System.out.println(cacheUser2.getName());
// 将用户信息数据从缓存中移除
cache.evict(id);
System.out.println(cache.get(id, User.class));
}
}
运行结果如下:
缓存测试
缓存测试
null
spring 缓存注解
完整代码示例:UserServiceTest.java
关于 cache 的支持,你可以阅读以下文档。
- 项目结构
和上面的一样
- User.java
import java.io.Serializable;
public class User implements Serializable {
private Long id;
private String name;
public User(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
if (id != null ? !id.equals(user.id) : user.id != null) return false;
return name != null ? name.equals(user.name) : user.name == null;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
}
- UserService.java & UserServiceImpl.java
import com.ryo.cache.ehcache.spring.model.User;
import java.util.List;
public interface UserService {
/**
* 创建用户
* @param id
* @param name
*/
void createUser(final Long id, final String name);
/**
* 删除用户
* @param user
*/
void removeUser(User user);
/**
* 更新用户信息
* @param user
*/
void updateUser(User user);
/**
* 根据 ID 查询用户信息
* @param id 用户ID
* @return
*/
User queryUser(final Long id);
/**
* 查询用户列表
* @return
*/
List<User> queryUserList();
}
import com.ryo.cache.ehcache.spring.model.User;
import com.ryo.cache.ehcache.spring.service.UserService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.LinkedList;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
/**
* 模仿数据库,暂时存储数据
*/
private List<User> userList = new LinkedList<>();
//key为参数中User对象的id,缓存指定id对应的Employee对象
@Cacheable(value = "annotation.cache", key = "'create_' + #id")
@Override
public void createUser(Long id, String name) {
System.out.println("创建用户:id: "+id+", name: "+name);
User user = new User(id, name);
userList.add(user);
}
//key为参数中User对象的id,缓存指定id对应的Employee对象
@Cacheable(value = "annotation.cache", key = "'query_' +#id")
@Override
public User queryUser(Long id) {
System.out.println("查询用户:id: "+id);
for(User user : userList) {
if(user.getId().equals(id)) {
return user;
}
}
return null;
}
@CacheEvict(value = "annotation.cache", key = "'remove_'+#user.getId()")
@Override
public void removeUser(User user) {
System.out.println("删除用户:user: "+user);
if(userList.contains(user)) {
int index = userList.indexOf(user);
userList.remove(index);
} else {
System.out.println("未发现对应用户!");
}
}
//key为参数中User对象的id,缓存指定id对应的Employee对象
@CachePut(value = "annotation.cache", key = "'update_'+#user.id")
@Override
public void updateUser(User user) {
System.out.println("更新用户:user: "+user);
for(int i = 0; i < userList.size(); i++) {
User original = userList.get(i);
if(original.getId().equals(user.getId())) {
userList.set(i, user);
return;
}
}
System.out.println("未发现对应用户!");
}
@Override
public List<User> queryUserList() {
System.out.println("查询用户列表:");
return userList;
}
}
- UserServiceTest.java
为了节约篇幅,每个测试的结果直接放在对应得到方法之上。
import com.ryo.cache.ehcache.spring.model.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext-cache.xml")
public class UserServiceTest {
@Autowired
private UserService userService;
// 查询用户列表:
// []
// 创建用户:id: 1, name: 1L first time
// 创建用户:id: 2, name: 2L first time
// 查询用户列表:
// [User{id=1, name='1L first time'}, User{id=2, name='2L first time'}]
@Test
public void createUserTest() {
System.out.println(userService.queryUserList());
userService.createUser(1L, "1L first time");
userService.createUser(1L, "1L second time"); //第二次操作将不再进行
userService.createUser(2L, "2L first time");
System.out.println(userService.queryUserList());
}
// 查询用户列表:
// []
// 创建用户:id: 1, name: 1L first time
// 创建用户:id: 2, name: 2L first time
// 查询用户:id: 1
// User{id=1, name='1L first time'}
// User{id=1, name='1L first time'}
// 查询用户:id: 2
// User{id=2, name='2L first time'}
@Test
public void queryUserTest() {
System.out.println(userService.queryUserList());
//1. 初始化数据
userService.createUser(1L, "1L first time");
userService.createUser(2L, "2L first time");
//查询用户
System.out.println(userService.queryUser(1L));
System.out.println(userService.queryUser(1L));
System.out.println(userService.queryUser(2L));
}
// 查询用户列表:
// []
// 创建用户:id: 1, name: 1L first time
// 创建用户:id: 2, name: 2L first time
// 更新用户:user: User{id=1, name='1L updated once'}
// 查询用户:id: 1
// User{id=1, name='1L updated once'}
// 更新用户:user: User{id=1, name='1L updated twice'}
// User{id=1, name='1L updated once'}
@Test
public void updateUserTest() {
System.out.println(userService.queryUserList());
//1. 初始化数据
userService.createUser(1L, "1L first time");
userService.createUser(2L, "2L first time");
//2. 更新数据
userService.updateUser(new User(1L, "1L updated once"));
System.out.println(userService.queryUser(1L));
userService.updateUser(new User(1L, "1L updated twice"));
System.out.println(userService.queryUser(1L));
}
// 查询用户列表:
// []
// 创建用户:id: 1, name: 1L first time
// 创建用户:id: 2, name: 2L first time
// 删除用户:user: User{id=1, name='1L first time'}
// 查询用户:id: 1
// null
// 删除用户:user: User{id=1, name='1L first time'}
// 未发现对应用户!
// null
@Test
public void removeUserTest() {
System.out.println(userService.queryUserList());
//1. 初始化数据
userService.createUser(1L, "1L first time");
userService.createUser(2L, "2L first time");
//2. 删除数据
userService.removeUser(new User(1L, "1L first time"));
System.out.println(userService.queryUser(1L));
userService.removeUser(new User(1L, "1L first time"));
System.out.println(userService.queryUser(1L));
}
}
spring boot 整合
完整代码地址:spring-boot-ehcache