转自: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