转自:http://lib.csdn.net/article/java/65506
题外话: Spring 5中已经摘除了对Guava caching的使用,转而使用Caffeine.详见官方信息SPR-13797
本地缓存,之前一直用Guava Cache,最近spring-boot推荐使用Caffeine Cache。
主要的三种本地缓存性能对比:
简单几步,就可以在spring-boot中配置和使用Caffeine Cache:
-
引入依赖:
<!-- local cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency> -
配置:
有两种方法:- application.yml配置文件中配置:
- 优点:简单
- 缺点:无法针对每个cache配置不同的参数,比如过期时长、最大容量
-
配置类中配置
- 优点:可以针对每个cache配置不同的参数,比如过期时长、最大容量
- 缺点:要写一点代码
-
配置文件中直接配置:
spring:
cache:
type: CAFFEINE
cache-names:
- getPersonById
- name2
caffeine:
spec: maximumSize=500,expireAfterWrite=5s然后还要在主类中加上@EnableCaching注解:
@SpringBootApplication
@EnableScheduling
@EnableCaching
public class MySpringBootApplication -
另外一种更灵活的方法是在配置类中配置:
package com.xjj.config;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import com.github.benmanes.caffeine.cache.Caffeine;
/**
* Cache配置類,用于缓存数据
* @author XuJijun
*
*/
@Configuration
@EnableCaching
public class CacheConfig {
public static final int DEFAULT_MAXSIZE = 50000;
public static final int DEFAULT_TTL = 10;
/**
* 定義cache名稱、超時時長(秒)、最大容量
* 每个cache缺省:10秒超时、最多缓存50000条数据,需要修改可以在 构造方法的参数中指定。
*/
public enum Caches{
getPersonById(5), //有效期5秒
getSomething, //缺省10秒
getOtherthing(300, 1000), //5分钟,最大容量1000
;
Caches() {
}
Caches(int ttl) {
this.ttl = ttl;
}
Caches(int ttl, int maxSize) {
this.ttl = ttl;
this.maxSize = maxSize;
}
private int maxSize=DEFAULT_MAXSIZE; //最大數量
private int ttl=DEFAULT_TTL; //过期时间(秒)
public int getMaxSize() {
return maxSize;
}
public int getTtl() {
return ttl;
}
}
/**
* 创建基于Caffeine的Cache Manager
* @return
*/
@Bean
@Primary
public CacheManager caffeineCacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
ArrayList<CaffeineCache> caches = new ArrayList<CaffeineCache>();
for(Caches c : Caches.values()){
caches.add(new CaffeineCache(c.name(),
Caffeine.newBuilder().recordStats()
.expireAfterWrite(c.getTtl(), TimeUnit.SECONDS)
.maximumSize(c.getMaxSize())
.build())
);
}
cacheManager.setCaches(caches);
return cacheManager;
}
} -
代码中使用:
package com.xjj.service;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import com.xjj.dao.PersonDAO;
import com.xjj.entity.Person;
@Service
public class PersonService {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private PersonDAO personDao;
/**
* 根据id获取Person对象,使用缓存
* @param id
* @return Person对象
*/
@Cacheable(value="getPersonById", sync=true)
public Person getPersonById(int id){
logger.debug("getting data from database, personId={}", id);
return personDao.getPersonById(id);
}
} -
测试:
@Autowired
PersonService personService;
@Test
public void localCacheTest() throws JsonProcessingException, InterruptedException{
System.out.println("第一次:"); //从数据库中获取
Person p = personService.getPersonById(2);
logger.info("1st time: {}", objectMapper.writeValueAsString(p));
System.out.println("第二次:"); //从缓存中获取
p = personService.getPersonById(2);
logger.info("2nd time: {}", objectMapper.writeValueAsString(p));
Thread.sleep(5000);
System.out.println("第三次:"); //5秒钟超时后,从数据库中获取
p = personService.getPersonById(2);
logger.info("3rd time: {}", objectMapper.writeValueAsString(p));
System.out.println("第四次:"); //从缓存中获取
p = personService.getPersonById(2);
logger.info("4th time: {}", objectMapper.writeValueAsString(p));
}测试结果:
第一次:2016-11-02 17:11:13,105:DEBUG main (PersonService.java:27) - getting data from database, personId=2
2016-11-02 17:11:13,150:INFO main (HikariDataSource.java:93) - HikariPool-1 - Started.
2016-11-02 17:11:13,523:DEBUG main (BaseJdbcLogger.java:145) - ==> Preparing: SELECT id, first_name AS firstName, last_name AS lastName, birth_date AS birthDate, sex, phone_no AS phoneNo FROM test.t_person WHERE id=?;
2016-11-02 17:11:13,554:DEBUG main (BaseJdbcLogger.java:145) - ==> Parameters: 2(Integer)
2016-11-02 17:11:13,572:TRACE main (BaseJdbcLogger.java:151) - <== Columns: id, firstName, lastName, birthDate, sex, phoneNo
2016-11-02 17:11:13,573:TRACE main (BaseJdbcLogger.java:151) - <== Row: 2, 八, 李, 2015-08-07, F, 13625896321
2016-11-02 17:11:13,582:DEBUG main (BaseJdbcLogger.java:145) - <== Total: 1
2016-11-02 17:11:13,665:INFO main (MySpringBootApplicationTests.java:149) - 1st time: {"id":2,"firstName":"八","lastName":"李","birthDate":1438876800000,"sex":"F","phoneNo":"13625896321"}第二次:
2016-11-02 17:11:13,666:INFO main (MySpringBootApplicationTests.java:153) - 2nd time: {"id":2,"firstName":"八","lastName":"李","birthDate":1438876800000,"sex":"F","phoneNo":"13625896321"}
第三次:
2016-11-02 17:11:18,668:DEBUG main (PersonService.java:27) - getting data from database, personId=2
2016-11-02 17:11:18,669:DEBUG main (BaseJdbcLogger.java:145) - ==> Preparing: SELECT id, first_name AS firstName, last_name AS lastName, birth_date AS birthDate, sex, phone_no AS phoneNo FROM test.t_person WHERE id=?;
2016-11-02 17:11:18,670:DEBUG main (BaseJdbcLogger.java:145) - ==> Parameters: 2(Integer)
2016-11-02 17:11:18,671:TRACE main (BaseJdbcLogger.java:151) - <== Columns: id, firstName, lastName, birthDate, sex, phoneNo
2016-11-02 17:11:18,672:TRACE main (BaseJdbcLogger.java:151) - <== Row: 2, 八, 李, 2015-08-07, F, 13625896321
2016-11-02 17:11:18,672:DEBUG main (BaseJdbcLogger.java:145) - <== Total: 1
2016-11-02 17:11:18,673:INFO main (MySpringBootApplicationTests.java:159) - 3rd time: {"id":2,"firstName":"八","lastName":"李","birthDate":1438876800000,"sex":"F","phoneNo":"13625896321"}第四次:
2016-11-02 17:11:18,674:INFO main (MySpringBootApplicationTests.java:163) - 4th time: {"id":2,"firstName":"八","lastName":"李","birthDate":1438876800000,"sex":"F","phoneNo":"13625896321"}
- application.yml配置文件中配置:
Perfect!!!
完整的源代码:https://github.com/xujijun/my-spring-boot