zoukankan      html  css  js  c++  java
  • 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();
        }
    
  • 相关阅读:
    2020软件工程作业00——问题清单
    2020软件工程作业04
    2020软件工程作业03
    2020软件工程作业02
    2020软件工程作业01
    2020软件工程个人作业06——软件工程实践总结作业
    2020软件工程作业05
    2020软件工程作业00——问题清单
    2020软件工程作业04
    2020软件工程作业02
  • 原文地址:https://www.cnblogs.com/xunianchong/p/6901256.html
Copyright © 2011-2022 走看看