guava cache与spring集成
缓存的背景
缓存,在我们日常开发中是必不可少的一种解决性能问题的方法。简单的说,cache 就是为了提升系统性能而开辟的一块内存空间。在cpu进行计算的时候, 首先是读取寄存器,然后内存,再是硬盘。由于寄存器容量很小,不太适合存储我们需要快速读取的数据,放在硬盘中话,效率太低,所以大多数人将一些静态资源或者不经常修改的数据放在内存中。
缓存的作用
缓存的主要作用是暂时在内存中保存业务系统的数据处理结果,并且等待下次访问使用。在日常开发的很多场合,由于受限于硬盘 IO的性能或者我们自身业务系统的数据处理和获取可能非常费时,当我们发现我们的系统这个数据请求量很大的时候,频繁的IO和频繁的 逻辑处理会导致硬盘和CPU资源的瓶颈出现。缓存的作用就是将这些来自不易的数据保存在内存中,当有其他线程或者客户端需要查询相同 的数据资源时,直接从缓存的内存块中返回数据,这样不但可以提高系统的响应时间,同时也可以节省对这些数据的处理流程的资源消耗,整体上来说,系统性能会有大大的提升。
guava cache与spring整合
大家都清楚,相对于静态Map实现本地缓存而言guava cache提供了许多种对缓存管理策略,比如:缓存个数、缓存生存期、缓存提取策略(LRU)等, 也正是这样,guava cache在本地缓存层面上使用是开发人员的首选。而在企业开发中spring是用的最多的,如果将guava cache与spring整合,依靠spring强大的IOC和AOP在使用缓存时是很方便、 快捷的,而要实现spring与guava cache整合 只需要以下三个步骤就可以搞定:
建立spring-cache.xml
首先建立spring-cache.xml 里面配置spring对guava cache基本参数的管理,如下:
<?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:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:cache="http://www.springframework.org/schema/cache"
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-4.0.xsd">
<!--启动注解 进行guava cache 管理-->
<cache:annotation-driven cache-manager="cacheManager" proxy-target-class="true"/>
<bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">
<property name="cacheManagers">
<list>
<!--将guava cache交于spring管理 如果要实现redis 也可以加在这里-->
<ref bean="guavaCacheManager"/>
</list>
</property>
<property name="fallbackToNoOpCache" value="true"/>
</bean>
<!--配置guava cache需要缓存的key 以及建立方式-->
<bean id="guavaCacheManager" class="com.daojia.open.confluence.worker.common.GuavaCacheManager">
<property name="configMap">
<map key-type="java.lang.String" value-type="com.google.common.cache.CacheBuilder">
<entry key="indexReptileKeyValue" value-ref="defaultCacheBuilder"/>
</map>
</property>
</bean>
<!--设置guava cache缓存策略 生存期为24小时 最大100个缓存数-->
<bean id="defaultCacheBuilder"
class="com.google.common.cache.CacheBuilder"
factory-method="from">
<constructor-arg value="maximumSize=100, expireAfterWrite=24h"/>
</bean>
</beans>
实现spring对外提供的接口
上面配置了将guavaCacheManager交于spring管理,那么久要实现这个管理类,该类如果要被spring容器管理的话需要 实现AbstractTransactionSupportingCacheManager接口,该接口支持事物回滚,当缓存失败,会将错误数据还原。具体实现如下:
package com.daojia.open.confluence.worker.common;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Maps;
import org.springframework.cache.Cache;
import org.springframework.cache.transaction.AbstractTransactionSupportingCacheManager;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
/**
* guavacache支持事务回滚,重写manager。
* cache的构建使用builder配置构建
*/
public class GuavaCacheManager extends AbstractTransactionSupportingCacheManager {
private final ConcurrentMap<String, Cache> cacheMap = Maps.newConcurrentMap();
private boolean dynamic = true;
private Map<String, CacheBuilder> builderMap = Maps.newHashMap();
private boolean allowNullValues = true;
@Override
protected Collection<? extends Cache> loadCaches() {
Collection<Cache> values = cacheMap.values();
return values;
}
@Override
public Cache getCache(String name) {
Cache cache = this.cacheMap.get(name);
if (cache == null && this.dynamic) {
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null && this.builderMap.containsKey(name)) {
CacheBuilder builder = this.builderMap.get(name);
cache = createGuavaCache(name, builder);
this.cacheMap.put(name, cache);
}
}
}
return cache;
}
protected Cache createGuavaCache(String name, CacheBuilder builder) {
com.google.common.cache.Cache<Object, Object> cache = null;
if(builder == null){
cache = CacheBuilder.newBuilder().build();
}else{
cache = builder.build();
}
return new GuavaCache(name, cache, isAllowNullValues());
}
public boolean isAllowNullValues() {
return this.allowNullValues;
}
public void setConfigMap(Map<String, CacheBuilder> configMap) {
this.builderMap = configMap;
}
}
这仅仅是对guava cache管理 还需要一个具体的缓存操作类,该类也是一样要被spring管理,要实现一个cache接口,该接口是spring对外缓存管理的统一接口,只要实现该 接口的缓存,都能被spring管理起来,比如guava cache 如下:
package com.daojia.open.confluence.worker.common;
import com.daojia.open.confluence.worker.utils.JsonMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
public class GuavaCache implements Cache {
private static Logger log = LoggerFactory.getLogger(GuavaCache.class);
private final JsonMapper mapper = new JsonMapper();
private static final Object NULL_HOLDER = new NullHolder();
private final String name;
private final com.google.common.cache.Cache<Object, Object> cache;
private final boolean allowNullValues;
public GuavaCache(String name, com.google.common.cache.Cache<Object, Object> cache) {
this(name, cache, true);
}
public GuavaCache(String name, com.google.common.cache.Cache<Object, Object> cache, boolean allowNullValues) {
Assert.notNull(name, "Name must not be null");
Assert.notNull(cache, "Cache must not be null");
this.name = name;
this.cache = cache;
this.allowNullValues = allowNullValues;
}
@Override
public String getName() {
return this.name;
}
@Override
public Object getNativeCache() {
return this.cache;
}
@Override
public ValueWrapper get(Object key) {
key = getKey(key.toString());
Object value = this.cache.getIfPresent(key);
log.info("获取缓存key={},获取对象={}", key, mapper.toJson(value));
return toWrapper(value);
}
@Override
public <T> T get(Object key, Class<T> type) {
key = getKey(key.toString());
Object value = fromStoreValue(this.cache.getIfPresent(key));
log.info("获取缓存key={},获取对象={}", key, mapper.toJson(value));
if (value != null && type != null && !type.isInstance(value)) {
throw new IllegalStateException("Cached value is not of required type [" + type.getName() + "]: " + value);
}
return (T) value;
}
@Override
public void put(Object key, Object value) {
key = getKey(key.toString());
this.cache.put(key, toStoreValue(value));
log.info("存入缓存key=={},存入对象={}", key, mapper.toJson(value));
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
try {
PutIfAbsentCallable callable = new PutIfAbsentCallable(value);
Object result = this.cache.get(key, callable);
return (callable.called ? null : toWrapper(result));
}
catch (ExecutionException ex) {
throw new IllegalStateException(ex);
}
}
@Override
public void evict(Object key) {
this.cache.invalidate(key);
log.info("删除缓存key={}",key);
}
@Override
public void clear() {
this.cache.invalidateAll();
log.info("清空guavacache所有缓存");
}
private ValueWrapper toWrapper(Object value) {
return (value != null ? new SimpleValueWrapper(fromStoreValue(value)) : null);
}
protected Object fromStoreValue(Object storeValue) {
if (this.allowNullValues && storeValue == NULL_HOLDER) {
return null;
}
return storeValue;
}
public final boolean isAllowNullValues() {
return this.allowNullValues;
}
@SuppressWarnings("serial")
private static class NullHolder implements Serializable {
}
protected Object toStoreValue(Object userValue) {
if (this.allowNullValues && userValue == null) {
return NULL_HOLDER;
}
return userValue;
}
private class PutIfAbsentCallable implements Callable<Object> {
private final Object value;
private boolean called;
public PutIfAbsentCallable(Object value) {
this.value = value;
}
@Override
public Object call() throws Exception {
this.called = true;
return toStoreValue(this.value);
}
}
/**实现key增加cache名称**/
private String getKey(String key) {
return name + "_" + key;
}
}
编写sqel语法 对缓存进行管理
当完成这上面两个步骤之后,表明你的guava cache已被spring管理起来了,这时可以熟悉一下sqel注释语法,这是spring 对缓存进行注解管理用到常用语法,比如获取缓存:
/*当使用到该方法的时候 spring会首先判断缓存中是否含有该key的值 ,如果有则从本地缓存中获取
并以你输入的参数indexReptileKey为key获取,否则从执行方法体中的获取 并将获取的数据放入到缓存中*/
@Cacheable(value = "indexReptileKeyValue", key = "#indexReptileKey")
public List<IndexReptilePJO> getReptile(int indexReptileKey) throws Exception {
LOGGER.info("不走guava cache获取参数");
return super.handlerindexReptile();
}
放入缓存如下:
/*设置某个值的时候,想将该值存入缓存 则用这个注解 将你需要设置的值设置到缓存中
另一个方法在获取的时候就是从缓存中获取*/
@CachePut(value = "indexReptileKeyValue", key = "#indexReptileKey")
public List<IndexReptilePJO> setReptile(int indexReptileKey) throws Exception {
LOGGER.info("将树节点项目路径 存入guava cache中");
return super.handlerindexReptile();
}
guava cache与spring集成的更多相关文章
- Spring cache简单使用guava cache
Spring cache简单使用 前言 spring有一套和各种缓存的集成方式.类似于sl4j,你可以选择log框架实现,也一样可以实现缓存实现,比如ehcache,guava cache. [TOC ...
- Guava Cache探索及spring项目整合GuavaCache实例
背景 对于高频访问但是低频更新的数据我们一般会做缓存,尤其是在并发量比较高的业务里,原始的手段我们可以使用HashMap或者ConcurrentHashMap来存储. 这样没什么毛病,但是会面临一个问 ...
- Spring Boot 揭秘与实战(二) 数据缓存篇 - Guava Cache
文章目录 1. Guava Cache 集成 2. 个性化配置 3. 源代码 本文,讲解 Spring Boot 如何集成 Guava Cache,实现缓存. 在阅读「Spring Boot 揭秘与实 ...
- Spring配置cache(concurrentHashMap,guava cache、redis实现)附源码
在应用程序中,数据一般是存在数据库中(磁盘介质),对于某些被频繁访问的数据,如果每次都访问数据库,不仅涉及到网络io,还受到数据库查询的影响:而目前通常会将频繁使用,并且不经常改变的数据放入缓存中,从 ...
- 是什么让spring 5放弃了使用Guava Cache?
一路走来,Spring社区从刚开始的核心模块一直发展到现在,最近Sping5也完成了M5的发布, 相信不久之后第一个RELEASE版本也会发布.里面有很多特性是和即将要发布的JAVA 9息息相关的.今 ...
- spring boot guava cache 缓存学习
http://blog.csdn.net/hy245120020/article/details/78065676 ****************************************** ...
- 手把手教学在Springboot中搭建使用Guava cache,包教包会,不会我输一包辣条给你
guava cache使用简介 概述 缓存是日常开发中经常应用到的一种技术手段,合理的利用缓存可以极大的改善应用程序的性能. Guava官方对Cache的描述连接 缓存在各种各样的用例中非常有用.例 ...
- Spring集成GuavaCache实现本地缓存
Spring集成GuavaCache实现本地缓存: 一.SimpleCacheManager集成GuavaCache 1 package com.bwdz.sp.comm.util.test; 2 3 ...
- 从零开始学 Java - Spring 集成 Memcached 缓存配置(二)
Memcached 客户端选择 上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个: Memc ...
随机推荐
- js-页面需展示大量图片时,采用lyz.delayLoading.min.js,图片在屏幕时加载显示
本文本内容拷贝至:https://blog.csdn.net/xuanwuziyou/article/details/48199123 当一个网页中有大量图片时,浏览器会逐个去下载这些图片,等全部下载 ...
- echarts 金字塔
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Codeforces 333E Summer Earnings(bitset)
题目链接 Summer Earnings 类似MST_Kruskal的做法,连边后sort. 然后对于每条边,依次处理下来,当发现存在三角形时即停止.(具体细节见代码) 答案即为发现三角形时当前所在边 ...
- c++ concurrency serial 1: introduction
platform: vs2012 Code#include <iostream> #include <thread> using namespace std; void Fun ...
- LeetCode 205 Isomorphic Strings(同构的字符串)(string、vector、map)(*)
翻译 给定两个字符串s和t,决定它们是否是同构的. 假设s中的元素被替换能够得到t,那么称这两个字符串是同构的. 在用一个字符串的元素替换还有一个字符串的元素的过程中.所有字符的顺序必须保留. 没有两 ...
- openpyxl的使用记录
脚本功能描述: 读取指定文件夹内的.xlsx文件,遍历提取整理信息保存到另一指定文件夹中 import openpyxl import os import shutil city='城市名' def ...
- Redis简单介绍以及数据类型存储
因为我们在大型互联网项目其中.用户訪问量比較大,比較多.会产生并发问题,对于此.我们该怎样解决呢.Redis横空出世,首先,我们来简单的认识一下Redis.具体介绍例如以下所看到的: Redis是一个 ...
- Eclipse 安装(Oxygen版本)
Eclipse 安装(Oxygen版本) Eclipse 最新版本 Eclipse Neon,这个首次鼓励用户使用 Eclipse Installer 来做安装,这是一种由Eclipse Oomph提 ...
- 【Python】输出程序运行的百分比
对于一些大型的Python程序.我们须要在命令行输出其百分比,显得更加友好,以免被人误会程序陷入死循环.假死的窗口. 关键是利用到不换行的输出符\r,\r的输出.将直接覆盖掉此行的内容. 比方例如以下 ...
- javascript 转义函数
// 字符转义 html2Escape(sHtml) { return sHtml.replace(/[<>&"]/g, function(c) { return { ' ...