SpringBoot实践之---集成Spring cache和EhCache
声明式缓存
Spring 定义 CacheManager 和 Cache 接口用来统一不同的缓存技术。例如 JCache、 EhCache、 Hazelcast、 Guava、 Redis 等。在使用 Spring 集成 Cache 的时候,我们需要注册实现的 CacheManager 的 Bean。
Spring Boot 为我们自动配置了 JcacheCacheConfiguration、 EhCacheCacheConfiguration、HazelcastCacheConfiguration、GuavaCacheConfiguration、RedisCacheConfiguration、SimpleCacheConfiguration 等。
默认使用 ConcurrenMapCacheManager
在我们不使用其他第三方缓存依赖的时候,springboot自动采用ConcurrenMapCacheManager作为缓存管理器。
引入依赖
build.gradle中
//支持Spring cache
compile("org.springframework.boot:spring-boot-starter-cache")
maven的pom.xml中
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
编写实体类:
package com.great.cache;
public class Book {
private String isbn;
private String title;
public Book(String isbn, String title) {
this.isbn = isbn;
this.title = title;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
接口类和接口实现类
public interface BookRepository {
Book getByIsbn(String isbn);
Book getByIsbns(String isbn);
Book setByIsbns(String isbn);
}
-------------------------
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
@Component
public class SimpleBookRepository implements BookRepository {
@Override
@Cacheable("bookstest")
public Book getByIsbn(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book");
}
@Cacheable(value = "book", key = "#isbn")
public Book getByIsbns(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book="+isbn);
}
@CachePut(value = "book", key = "#isbn")
public Book setByIsbns(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book222="+isbn);
}
这个你可以写一个很复杂的数据查询操作,比如操作mysql、nosql等等。为了演示这个栗子,我只做了一下线程的延迟操作,当作是查询数据库的时间。
测试验证类
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class AppRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(AppRunner.class);
private final BookRepository bookRepository;
public AppRunner(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
@Override
public void run(String... args) throws Exception {
logger.info(".... Fetching books");
logger.info("isbn-1234 -->" + bookRepository.getByIsbns("isbn-1234").getTitle());
logger.info("isbn-4567 -->" + bookRepository.getByIsbns("isbn-4567").getTitle());
logger.info("isbn-1234 -->" + bookRepository.getByIsbns("isbn-1234").getTitle());
logger.info("isbn-4567 -->" + bookRepository.setByIsbns("isbn-4567").getTitle());
logger.info("isbn-1234 -->" + bookRepository.getByIsbns("isbn-1234").getTitle());
logger.info("isbn-1234 -->" + bookRepository.getByIsbns("isbn-4567").getTitle());
}
}
运行结果为:
2018-02-28 17:21:31.600 INFO 51100 --- [ restartedMain] com.great.cache.AppRunner : .... Fetching books
2018-02-28 17:21:34.613 INFO 51100 --- [ restartedMain] com.great.cache.AppRunner : isbn-1234 -->Some book=isbn-1234
2018-02-28 17:21:37.614 INFO 51100 --- [ restartedMain] com.great.cache.AppRunner : isbn-4567 -->Some book=isbn-4567
2018-02-28 17:21:37.615 INFO 51100 --- [ restartedMain] com.great.cache.AppRunner : isbn-1234 -->Some book=isbn-1234
2018-02-28 17:21:40.617 INFO 51100 --- [ restartedMain] com.great.cache.AppRunner : isbn-4567 -->Some book222=isbn-4567
2018-02-28 17:21:40.617 INFO 51100 --- [ restartedMain] com.great.cache.AppRunner : isbn-1234 -->Some book=isbn-1234
2018-02-28 17:21:40.617 INFO 51100 --- [ restartedMain] com.great.cache.AppRunner : isbn-4567 -->Some book222=isbn-4567
补充:要使缓存生效,还必须在springboot主启动类上面加上 @EnableCaching
@EnableCaching
public class MainApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
另外使用缓存的地方需要相应的标注
对于缓存的操作,主要有:@Cacheable、@CachePut、@CacheEvict。
@Cacheable
Spring 在执行 @Cacheable 标注的方法前先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,执行该方法并将方法返回值放进缓存。
参数: value缓存名、 key缓存键值、 condition满足缓存条件、unless否决缓存条件
@Cacheable(value = "user", key = "#id")
public User findById(final Long id) {
System.out.println("cache miss, invoke find by id, id:" + id);
for (User user : users) {
if (user.getId().equals(id)) {
return user;
}
}
return null;
}
@CachePut
和 @Cacheable 类似,但会把方法的返回值放入缓存中, 主要用于数据新增和修改方法。
@CachePut(value = "user", key = "#user.id")
public User save(User user) {
users.add(user);
return user;
}
@CacheEvict
方法执行成功后会从缓存中移除相应数据。
参数: value缓存名、 key缓存键值、 condition满足缓存条件、 unless否决缓存条件、 allEntries是否移除所有数据(设置为true时会移除所有缓存)
@CacheEvict(value = "user", key = "#user.id") // 移除指定key的数据
public User delete(User user) {
users.remove(user);
return user;
}
@CacheEvict(value = "user", allEntries = true) // 移除所有数据
public void deleteAll() {
users.clear();
}
使用 EhCache
引入EhCache,在build.gradle中加入
//支持Encache
compile("net.sf.ehcache:ehcache")
在resources目录下创建了ehcache.xml的配置文件,然后在application.properties 设置type为ehcache(intellij有明确的提示):
<ehcache>
<!-- 指定一个文件目录,当EHCache把数据写到硬盘上时,将把数据写到这个文件目录下 -->
<diskStore path="java.io.tmpdir"/>
<!-- 设定缓存的默认数据过期策略 -->
<cache name="book" maxElementsInMemory="10000" />
<defaultCache
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="10"
timeToLiveSeconds="120"
diskPersistent="false"
memoryStoreEvictionPolicy="LRU"
diskExpiryThreadIntervalSeconds="120"/>
<!-- maxElementsInMemory 内存中最大缓存对象数,看着自己的heap大小来搞 -->
<!-- eternal:true表示对象永不过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds属性,默认为false -->
<!-- maxElementsOnDisk:硬盘中最大缓存对象数,若是0表示无穷大 -->
<!-- overflowToDisk:true表示当内存缓存的对象数目达到了maxElementsInMemory界限后,
会把溢出的对象写到硬盘缓存中。注意:如果缓存的对象要写入到硬盘中的话,则该对象必须实现了Serializable接口才行。-->
<!-- diskSpoolBufferSizeMB:磁盘缓存区大小,默认为30MB。每个Cache都应该有自己的一个缓存区。-->
<!-- diskPersistent:是否缓存虚拟机重启期数据 -->
<!-- diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认为120秒 -->
<!-- timeToIdleSeconds: 设定允许对象处于空闲状态的最长时间,以秒为单位。当对象自从最近一次被访问后,
如果处于空闲状态的时间超过了timeToIdleSeconds属性值,这个对象就会过期,
EHCache将把它从缓存中清空。只有当eternal属性为false,该属性才有效。如果该属性值为0,
则表示对象可以无限期地处于空闲状态 -->
<!-- timeToLiveSeconds:设定对象允许存在于缓存中的最长时间,以秒为单位。当对象自从被存放到缓存中后,
如果处于缓存中的时间超过了 timeToLiveSeconds属性值,这个对象就会过期,
EHCache将把它从缓存中清除。只有当eternal属性为false,该属性才有效。如果该属性值为0,
则表示对象可以无限期地存在于缓存中。timeToLiveSeconds必须大于timeToIdleSeconds属性,才有意义 -->
<!-- memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,
Ehcache将会根据指定的策略去清理内存。可选策略有:LRU(最近最少使用,默认策略)、
FIFO(先进先出)、LFU(最少访问次数)。-->
</ehcache>
application.properties 中增加
#encache配置
spring.cache.type=ehcache
spring.cache.ehcache.config=ehcache.xml
代码层级使用同Spring cache
上一篇: Tomcat配置文件server.xml配置参数详解
下一篇: shared_ptr的使用和陷阱