缓存,在咱们平常开发中是必不可少的一种解决性能问题的方法。简单的说,cache 就是为了提高系统性能而开辟的一块内存空间。在cpu进行计算的时候, 首先是读取寄存器,而后内存,再是硬盘。因为寄存器容量很小,不太适合存储咱们须要快速读取的数据,放在硬盘中话,效率过低,因此大多数人将一些静态资源或者不常常修改的数据放在内存中。 java
缓存的主要做用是暂时在内存中保存业务系统的数据处理结果,而且等待下次访问使用。在平常开发的不少场合,因为受限于硬盘 IO的性能或者咱们自身业务系统的数据处理和获取可能很是费时,当咱们发现咱们的系统这个数据请求量很大的时候,频繁的IO和频繁的 逻辑处理会致使硬盘和CPU资源的瓶颈出现。缓存的做用就是将这些来自不易的数据保存在内存中,当有其余线程或者客户端须要查询相同 的数据资源时,直接从缓存的内存块中返回数据,这样不但能够提升系统的响应时间,同时也能够节省对这些数据的处理流程的资源消耗,总体上来讲,系统性能会有大大的提高。redis
你们都清楚,相对于静态Map实现本地缓存而言guava cache提供了许多种对缓存管理策略,好比:缓存个数、缓存生存期、缓存提取策略(LRU)等, 也正是这样,guava cache在本地缓存层面上使用是开发人员的首选。而在企业开发中spring是用的最多的,若是将guava cache与spring整合,依靠spring强大的IOC和AOP在使用缓存时是很方便、 快捷的,而要实现spring与guava cache整合 只须要如下三个步骤就能够搞定:spring
首先创建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>
上面配置了将guavaCacheManager交于spring管理,那么久要实现这个管理类,该类若是要被spring容器管理的话须要 实现AbstractTransactionSupportingCacheManager接口,该接口支持事物回滚,当缓存失败,会将错误数据还原。具体实现以下:app
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 以下:ide
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; } }
当完成这上面两个步骤以后,代表你的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(); }
放入缓存以下:ui
/*设置某个值的时候,想将该值存入缓存 则用这个注解 将你须要设置的值设置到缓存中 另外一个方法在获取的时候就是从缓存中获取*/ @CachePut(value = "indexReptileKeyValue", key = "#indexReptileKey") public List<IndexReptilePJO> setReptile(int indexReptileKey) throws Exception { LOGGER.info("将树节点项目路径 存入guava cache中"); return super.handlerindexReptile(); }