Spring Cache缓存技术的介绍 (2)

spring cache还可以与redis集成,提供分布式缓存的能力。

创建Application package heyikan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; @SpringBootApplication @EnableCaching public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

熟悉spring-boot项目的读者应该对此比较熟悉,spring-boot项目需要创建一个Application来启动整个应用。

@EnableCaching注解用于启用缓存,没有这个注解,我们后面的缓存功能将不会生效。

创建Controller package heyikan; import com.github.benmanes.caffeine.cache.Cache; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.CacheManager; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; import java.util.concurrent.ConcurrentMap; import java.util.function.Function; import java.util.stream.Collectors; @RestController public class QueryController { @Autowired private QueryService queryService; @GetMapping("/query") public ResponseEntity<?> query(String keyWord) { String result = queryService.query(keyWord); return ResponseEntity.ok(result); } @Autowired @SuppressWarnings("all") private CacheManager cacheManager; @GetMapping("/caches") public ResponseEntity<?> getCache() { Map<String, ConcurrentMap> cacheMap = cacheManager.getCacheNames().stream() .collect(Collectors.toMap(Function.identity(), name -> { Cache cache = (Cache) cacheManager.getCache(name).getNativeCache(); return cache.asMap(); })); return ResponseEntity.ok(cacheMap); } }

QueryController提供了两个Rest接口,query用于模拟耗时的查询请求,getCache用于获取当前的缓存内容。

QueryController中引入了QueryService依赖,它是提供查询和缓存功能的核心组件。

QueryController中引入了CacheManager依赖,它持有所有的缓存,并提供了遍历的API。

创建缓存组件 package heyikan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cache.annotation.CacheConfig; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service @CacheConfig(cacheNames = {"query-result", "demo"}) public class QueryService { private static Logger LOG = LoggerFactory.getLogger(QueryService.class); @Cacheable(unless = "#result.length() > 20") public String query(String keyWord) { LOG.info("do query by keyWord: {}", keyWord); String queryResult = doQuery(keyWord); return queryResult; } private String doQuery(String keyWord) { try { Thread.sleep(3000L); String result = "result of " + keyWord; return result; } catch (InterruptedException e) { throw new IllegalStateException(e); } } }

我们使用@CacheConfig配置缓存,如代码所示,数据将会同时缓存到"query-result"和"demo"中。

query方法是查询的入口,@Cacheable注解用于表示query方法的返回结果将被放到缓存中,默认以方法的参数作为key。

@Cacheable注解的unless属性补充了缓存的条件,按照代码所示,当query的返回结果其长度大于20的时候,就不会进行缓存。

doQuery方法代表实际的查询操作,模拟耗时的查询过程。

创建配置

application.yml文件内容如下:

spring: cache: caffeine: spec: maximumSize=500, expireAfterAccess=30s logging: pattern: console: "%-5level - %msg%n" level: - error - heyikan=ALL

spring.cache.caffeine.spec配置了两个缓存指标:

maximumSize
配置缓存的最大容量,当快要达到容量上限的时候,缓存管理器会根据一定的策略将部分缓存项移除。

expireAfterAccess
配置缓存项的过期机制,如代码所示当缓存项被访问后30秒将会过期,从而被移除。

技术要点 缓存的结构

在上文获取缓存的接口中,我们得到的结果是:

{ "query-result": { "spring": "result of spring" }, "demo": { "spring": "result of spring" } }

缓存的结构大概像Map<cacheName, Map<key, value>>,其中每一对key-value又称为一个缓存项。

上文中,我们缓存组件的query方法的返回结果,就是以参数为key,以结果为value,构建缓存项进行缓存的。

另外,我们配置的超时时间,也是以缓存项为粒度进行控制的。

包含缓存项的Map我们称为缓存实例,每一个实例有一个实例名(cacheName)。

cache结构相关的类图如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwyjdz.html