Spring Boot 缓存应用实践
点击上方 好好学java ,选择 星标 公众号
         
          
           
            
             
              
                
                 重磅资讯、干货,第一时间送达
                 
                
                 
                 
              
             
            
           
          
        
                
                 重磅资讯、干货,第一时间送达
                 
                
                 
                 
             今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招!
         
          
           
            
             
              
               
                 个人原创100W+访问量博客:点击前往,查看更多
                
              
             
            
           
          
       
               
                 个人原创100W+访问量博客:点击前往,查看更多
                
             来源:cnblogs.com/jeffwongishandsome
缓存是最直接有效提升系统性能的手段之一。个人认为用好用对缓存是优秀程序员的必备基本素质。本文结合实际开发经验,从简单概念原理和代码入手,一步一步搭建一个简单的二级缓存系统。
一、通用缓存接口
1、缓存基础算法
- 
    
FIFO(First In First Out),先进先出,和OS里的FIFO思路相同,如果一个数据最先进入缓存中,当缓存满的时候,应当把最先进入缓存的数据给移除掉。  - 
    
LFU(Least Frequently Used),最不经常使用,如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小。  - 
    
LRU(Least Recently Used),最近最少使用,如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据移除。  
2、接口定义
package com.power.demo.cache.contract;
import java.util.function.Function;
/**
 * 缓存提供者接口
 **/
public interface CacheProviderService {
    /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     **/
    
      
       extends 
       Object> T 
       get(
       String key);
       
       
    
       /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     **/
       
    
       
        extends 
        Object> T 
        get(
        String key, 
        Function<
        String, T> 
        function);
        
        
    
        /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParm function函数的调用参数
     **/
        
    
        
         extends 
         Object, M 
         extends 
         Object> T 
         get(
         String key, 
         Function
          
          function, M funcParm);
          
          
    
          /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
          
    
          
           extends 
           Object> T 
           get(
           String key, 
           Function<
           String, T> 
           function, Long expireTime);
           
           
    
           /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParm function函数的调用参数
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
           
    
           
            extends 
            Object, M 
            extends 
            Object> T 
            get(
            String key, 
            Function
             
             function, M funcParm, Long expireTime);
             
             
    
             /**
     * 设置缓存键值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     **/
             
    
             
              extends 
              Object> 
              void 
              set(
              String key, T obj);
              
              
    
              /**
     * 设置缓存键值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
              
    
              
               extends 
               Object> 
               void 
               set(
               String key, T obj, Long expireTime);
               
               
    
               /**
     * 移除缓存
     *
     * @param key 缓存键 不可为空
     **/
               
    
               void remove(
               String key);
               
               
    
               /**
     * 是否存在缓存
     *
     * @param key 缓存键 不可为空
     **/
               
    
               boolean contains(
               String key);
               
}
               
               
              
             
            
           
          
         
        
       
  二、本地缓存
1、什么是Guava
2、添加依赖
<dependency>
    <groupId>com.google.guavagroupId>
    <artifactId>guavaartifactId>
dependency>
  3、实现接口
/*
 * 本地缓存提供者服务 (Guava Cache)
 * */
@Configuration
@ComponentScan(basePackages = AppConst.BASE_PACKAGE_NAME)
@Qualifier("localCacheService")
public class LocalCacheProviderImpl implements CacheProviderService {
    private static Map<String, Cache<String, Object>> _cacheMap = Maps.newConcurrentMap();
    static {
        Cache<String, Object> cacheContainer = CacheBuilder.newBuilder()
                .maximumSize(AppConst.CACHE_MAXIMUM_SIZE)
                .expireAfterWrite(AppConst.CACHE_MINUTE, TimeUnit.MILLISECONDS)//最后一次写入后的一段时间移出
                //.expireAfterAccess(AppConst.CACHE_MINUTE, TimeUnit.MILLISECONDS) //最后一次访问后的一段时间移出
                .recordStats()//开启统计功能
                .build();
        _cacheMap.put(String.valueOf(AppConst.CACHE_MINUTE), cacheContainer);
    }
    /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     **/
    public 
      
       extends 
       Object> T 
       get(
       String key) {
       
        T obj = 
       get(key, 
       null, 
       null, AppConst.CACHE_MINUTE);
       
       
        
       return obj;
       
    }
       
       
    
       /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     **/
       
    
       public 
       
        extends 
        Object> T 
        get(
        String key, 
        Function<
        String, T> 
        function) {
        
        T obj = 
        get(key, 
        function, key, AppConst.CACHE_MINUTE);
        
        
        
        return obj;
        
    }
        
        
    
        /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParm function函数的调用参数
     **/
        
    
        public 
        
         extends 
         Object, M 
         extends 
         Object> T 
         get(
         String key, 
         Function
          
          function, M funcParm) {
          
        T obj = 
          get(key, 
          function, funcParm, AppConst.CACHE_MINUTE);
          
          
        
          return obj;
          
    }
          
          
    
          /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
          
    
          public 
          
           extends 
           Object> T 
           get(
           String key, 
           Function<
           String, T> 
           function, Long expireTime) {
           
        T obj = 
           get(key, 
           function, key, expireTime);
           
           
        
           return obj;
           
    }
           
           
    
           /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParm function函数的调用参数
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
           
    
           public 
           
            extends 
            Object, M 
            extends 
            Object> T 
            get(
            String key, 
            Function
             
             function, M funcParm, Long expireTime) {
             
        T obj = 
             null;
             
        
             if (StringUtils.isEmpty(key) == 
             true) {
             
            
             return obj;
             
        }
             
             
        expireTime = getExpireTime(expireTime);
             
             
        Cache<
             String, 
             Object> cacheContainer = getCacheContainer(expireTime);
             
             
        
             try {
             
            
             if (
             function == null) {
             
                obj = (T) cacheContainer.getIfPresent(key);
             
            } 
             else {
             
                final Long cachedTime = expireTime;
             
                obj = (T) cacheContainer.get(key, () -> {
             
                    T retObj = 
             function.apply(funcParm);
             
                    
             return retObj;
             
                });
             
            }
             
        } 
             catch (Exception e) {
             
            e.printStackTrace();
             
        }
             
             
        
             return obj;
             
    }
             
             
    
             /**
     * 设置缓存键值 直接向缓存中插入值,这会直接覆盖掉给定键之前映射的值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     **/
             
    
             public 
             
              extends 
              Object> 
              void 
              set(
              String key, T obj) {
              
              
        
              set(key, obj, AppConst.CACHE_MINUTE);
              
    }
              
              
    
              /**
     * 设置缓存键值 直接向缓存中插入值,这会直接覆盖掉给定键之前映射的值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
              
    
              public 
              
               extends 
               Object> 
               void 
               set(
               String key, T obj, Long expireTime) {
               
        
               if (StringUtils.isEmpty(key) == 
               true) {
               
            
               return;
               
        }
               
               
        
               if (obj == 
               null) {
               
            
               return;
               
        }
               
               
        expireTime = getExpireTime(expireTime);
               
               
        Cache<
               String, 
               Object> cacheContainer = getCacheContainer(expireTime);
               
               
        cacheContainer.put(key, obj);
               
    }
               
               
    
               /**
     * 移除缓存
     *
     * @param key 缓存键 不可为空
     **/
               
    
               public 
               void remove(
               String key) {
               
        
               if (StringUtils.isEmpty(key) == 
               true) {
               
            
               return;
               
        }
               
               
        long expireTime = getExpireTime(AppConst.CACHE_MINUTE);
               
               
        Cache<
               String, 
               Object> cacheContainer = getCacheContainer(expireTime);
               
               
        cacheContainer.invalidate(key);
               
    }
               
               
    
               /**
     * 是否存在缓存
     *
     * @param key 缓存键 不可为空
     **/
               
    
               public 
               boolean contains(
               String key) {
               
        
               boolean exists = 
               false;
               
        
               if (StringUtils.isEmpty(key) == 
               true) {
               
            
               return exists;
               
        }
               
               
        
               Object obj = 
               get(key);
               
               
        
               if (obj != 
               null) {
               
            exists = 
               true;
               
        }
               
               
        
               return exists;
               
    }
               
               
    
               private 
               static Lock lock = 
               new ReentrantLock();
               
               
    
               private Cache<
               String, 
               Object> getCacheContainer(Long expireTime) {
               
               
        Cache<
               String, 
               Object> cacheContainer = 
               null;
               
        
               if (expireTime == 
               null) {
               
            
               return cacheContainer;
               
        }
               
               
        
               String mapKey = 
               String.valueOf(expireTime);
               
               
        
               if (_cacheMap.containsKey(mapKey) == 
               true) {
               
            cacheContainer = _cacheMap.get(mapKey);
               
            
               return cacheContainer;
               
        }
               
               
        
               try {
               
            lock.lock();
               
            cacheContainer = CacheBuilder.newBuilder()
               
                    .maximumSize(AppConst.CACHE_MAXIMUM_SIZE)
               
                    .expireAfterWrite(expireTime, TimeUnit.MILLISECONDS)
               //最后一次写入后的一段时间移出
               
                    
               //.expireAfterAccess(AppConst.CACHE_MINUTE, TimeUnit.MILLISECONDS) //最后一次访问后的一段时间移出
               
                    .recordStats()
               //开启统计功能
               
                    .build();
               
               
            _cacheMap.put(mapKey, cacheContainer);
               
               
        } 
               finally {
               
            lock.unlock();
               
        }
               
               
        
               return cacheContainer;
               
    }
               
               
    
               /**
     * 获取过期时间 单位:毫秒
     *
     * @param expireTime 传人的过期时间 单位毫秒 如小于1分钟,默认为10分钟
     **/
               
    
               private Long getExpireTime(Long expireTime) {
               
        Long result = expireTime;
               
        
               if (expireTime == 
               null || expireTime < AppConst.CACHE_MINUTE / 
               10) {
               
            result = AppConst.CACHE_MINUTE;
               
        }
               
               
        
               return result;
               
    }
               
}
               
              
             
            
           
          
         
        
       
  4、注意事项
  - 
    
expireAfterWrite:最后一次写入后的一段时间移出。  - 
    
expireAfterAccess:最后一次访问后的一段时间移出。  
三、分布式缓存
1、什么是Redis
Values:Strings、Hash、Lists、 Sets、 Sorted sets。考虑到Redis单线程操作模式,Value的粒度不应该过大,缓存的值越大,越容易造成阻塞和排队。
2、添加依赖
<dependency>
     <groupId>org.springframework.bootgroupId>
     <artifactId>spring-boot-starter-data-redisartifactId>
dependency>
  3、配置Redis
## Redis缓存相关配置
#Redis数据库索引(默认为0)
spring.redis.database=0
#Redis服务器地址
spring.redis.host=127.0.0.1
#Redis服务器端口
spring.redis.port=6379
#Redis服务器密码(默认为空)
spring.redis.password=123321
#Redis连接超时时间 默认:5分钟(单位:毫秒)
spring.redis.timeout=300000ms
#Redis连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=512
#Redis连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
#Redis连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
#Redis连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1ms
redisproperties
  /**
 * Redis缓存配置类
 */
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        return RedisCacheManager.create(connectionFactory);
    }
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //Jedis的Key和Value的序列化器默认值是JdkSerializationRedisSerializer
        //经实验,JdkSerializationRedisSerializer通过RedisDesktopManager看到的键值对不能正常解析
        //设置key的序列化器
        template.setKeySerializer(new StringRedisSerializer());
        ////设置value的序列化器 默认值是JdkSerializationRedisSerializer
        //使用Jackson序列化器的问题是,复杂对象可能序列化失败,比如JodaTime的DateTime类型
        // //使用Jackson2,将对象序列化为JSON
        // Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // //json转对象类,不设置默认的会将json转成hashmap
        // ObjectMapper om = new ObjectMapper();
        // om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        // jackson2JsonRedisSerializer.setObjectMapper(om);
        // template.setValueSerializer(jackson2JsonRedisSerializer);
        //将redis连接工厂设置到模板类中
        template.setConnectionFactory(factory);
        return template;
    }
// //自定义缓存key生成策略
// @Bean
// public KeyGenerator keyGenerator() {
// return new KeyGenerator() {
// @Override
// public Object generate(Object target, java.lang.reflect.Method method, Object... params) {
// StringBuffer sb = new StringBuffer();
// sb.append(target.getClass().getName());
// sb.append(method.getName());
// for (Object obj : params) {
// if (obj == null) {
// continue;
// }
// sb.append(obj.toString());
// }
// return sb.toString();
// }
// };
// }
}
  - 
    
JdkSerializationRedisSerializer:使用Java序列化;  - 
    
StringRedisSerializer:序列化String类型的key和value;  - 
    
GenericToStringSerializer:使用Spring转换服务进行序列化;  - 
    
JacksonJsonRedisSerializer:使用Jackson 1,将对象序列化为JSON;  - 
    
Jackson2JsonRedisSerializer:使用Jackson 2,将对象序列化为JSON;  - 
    
OxmSerializer:使用Spring O/X映射的编排器和解排器(marshaler和unmarshaler)实现序列化,用于XML序列化;  
  4、实现接口
@Configuration
@ComponentScan(basePackages = AppConst.BASE_PACKAGE_NAME)
@Qualifier("redisCacheService")
public class RedisCacheProviderImpl implements CacheProviderService {
    @Resource
    private RedisTemplate
      
       Object> redisTemplate;
       
       
    
       /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     **/
       
    
       public 
       
        extends 
        Object> T 
        get(
        String key) {
        
        T obj = 
        get(key, 
        null, 
        null, AppConst.CACHE_MINUTE);
        
        
        
        return obj;
        
    }
        
        
    
        /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     **/
        
    
        public 
        
         extends 
         Object> T 
         get(
         String key, 
         Function<
         String, T> 
         function) {
         
        T obj = 
         get(key, 
         function, key, AppConst.CACHE_MINUTE);
         
         
        
         return obj;
         
    }
         
         
    
         /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParm function函数的调用参数
     **/
         
    
         public 
         
          extends 
          Object, M 
          extends 
          Object> T 
          get(
          String key, 
          Function
           
           function, M funcParm) {
           
        T obj = 
           get(key, 
           function, funcParm, AppConst.CACHE_MINUTE);
           
           
        
           return obj;
           
    }
           
           
    
           /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
           
    
           public 
           
            extends 
            Object> T 
            get(
            String key, 
            Function<
            String, T> 
            function, Long expireTime) {
            
        T obj = 
            get(key, 
            function, key, expireTime);
            
            
        
            return obj;
            
    }
            
            
    
            /**
     * 查询缓存
     *
     * @param key 缓存键 不可为空
     * @param function 如没有缓存,调用该callable函数返回对象 可为空
     * @param funcParm function函数的调用参数
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
            
    
            public 
            
             extends 
             Object, M 
             extends 
             Object> T 
             get(
             String key, 
             Function
              
              function, M funcParm, Long expireTime) {
              
        T obj = 
              null;
              
        
              if (StringUtils.isEmpty(key) == 
              true) {
              
            
              return obj;
              
        }
              
              
        expireTime = getExpireTime(expireTime);
              
              
        
              try {
              
              
            ValueOperations
              
               Object> operations = redisTemplate.opsForValue();
               
            obj = (T) operations.get(key);
               
            
               if (
               function != null && obj == null) {
               
                obj = 
               function.apply(funcParm);
               
                
               if (obj != 
               null) {
               
                    
               set(key, obj, expireTime);
               //设置缓存信息
               
                }
               
            }
               
        } 
               catch (Exception e) {
               
            e.printStackTrace();
               
        }
               
               
        
               return obj;
               
    }
               
               
    
               /**
     * 设置缓存键值 直接向缓存中插入值,这会直接覆盖掉给定键之前映射的值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     **/
               
    
               public 
               
                extends 
                Object> 
                void 
                set(
                String key, T obj) {
                
                
        
                set(key, obj, AppConst.CACHE_MINUTE);
                
    }
                
                
    
                /**
     * 设置缓存键值 直接向缓存中插入值,这会直接覆盖掉给定键之前映射的值
     *
     * @param key 缓存键 不可为空
     * @param obj 缓存值 不可为空
     * @param expireTime 过期时间(单位:毫秒) 可为空
     **/
                
    
                public 
                
                 extends 
                 Object> 
                 void 
                 set(
                 String key, T obj, Long expireTime) {
                 
        
                 if (StringUtils.isEmpty(key) == 
                 true) {
                 
            
                 return;
                 
        }
                 
                 
        
                 if (obj == 
                 null) {
                 
            
                 return;
                 
        }
                 
                 
        expireTime = getExpireTime(expireTime);
                 
                 
        ValueOperations
                 
                  Object> operations = redisTemplate.opsForValue();
                  
                  
        operations.set(key, obj);
                  
                  
        redisTemplate.expire(key, expireTime, TimeUnit.MILLISECONDS);
                  
    }
                  
                  
    
                  /**
     * 移除缓存
     *
     * @param key 缓存键 不可为空
     **/
                  
    
                  public 
                  void remove(
                  String key) {
                  
        
                  if (StringUtils.isEmpty(key) == 
                  true) {
                  
            
                  return;
                  
        }
                  
                  
        redisTemplate.delete(key);
                  
    }
                  
                  
    
                  /**
     * 是否存在缓存
     *
     * @param key 缓存键 不可为空
     **/
                  
    
                  public 
                  boolean contains(
                  String key) {
                  
        
                  boolean exists = 
                  false;
                  
        
                  if (StringUtils.isEmpty(key) == 
                  true) {
                  
            
                  return exists;
                  
        }
                  
                  
        
                  Object obj = 
                  get(key);
                  
                  
        
                  if (obj != 
                  null) {
                  
            exists = 
                  true;
                  
        }
                  
                  
        
                  return exists;
                  
    }
                  
                  
    
                  /**
     * 获取过期时间 单位:毫秒
     *
     * @param expireTime 传人的过期时间 单位毫秒 如小于1分钟,默认为10分钟
     **/
                  
    
                  private Long getExpireTime(Long expireTime) {
                  
        Long result = expireTime;
                  
        
                  if (expireTime == 
                  null || expireTime < AppConst.CACHE_MINUTE / 
                  10) {
                  
            result = AppConst.CACHE_MINUTE;
                  
        }
                  
                  
        
                  return result;
                  
    }
                  
}
                  
                 
                
               
              
             
            
           
          
         
        
       
  四、缓存“及时”过期问题
五、二级缓存
##是否启用本地缓存
spring.power.isuselocalcache=1
##是否启用Redis缓存
spring.power.isuserediscache=1
  /*
* 支持多缓存提供程序多级缓存的缓存帮助类
* */
@Configuration
@ComponentScan(basePackages = AppConst.BASE_PACKAGE_NAME)
public class PowerCacheBuilder {
@Autowired
@Qualifier("localCacheService")
private CacheProviderService localCacheService;
@Autowired
@Qualifier("redisCacheService")
private CacheProviderService redisCacheService;
private static List_listCacheProvider = Lists.newArrayList(); 
private static final Lock providerLock = new ReentrantLock();
/**
* 初始化缓存提供者 默认优先级:先本地缓存,后分布式缓存
**/
private ListgetCacheProviders() { 
if (_listCacheProvider.size() > 0) {
return _listCacheProvider;
}
//线程安全
try {
providerLock.tryLock( 1000, TimeUnit.MILLISECONDS);
if (_listCacheProvider.size() > 0) {
return _listCacheProvider;
}
String isUseCache = ConfigUtil.getConfigVal(AppField.IS_USE_LOCAL_CACHE);
CacheProviderService cacheProviderService = null;
//启用本地缓存
if ( "1".equalsIgnoreCase(isUseCache)) {
_listCacheProvider.add(localCacheService);
}
isUseCache = ConfigUtil.getConfigVal(AppField.IS_USE_REDIS_CACHE);
//启用Redis缓存
if ( "1".equalsIgnoreCase(isUseCache)) {
_listCacheProvider.add(redisCacheService);
resetCacheVersion(); //设置分布式缓存版本号
}
PowerLogger.info( "初始化缓存提供者成功,共有" + _listCacheProvider.size() + "个");
} catch (Exception e) {
e.printStackTrace();
_listCacheProvider = Lists.newArrayList();
PowerLogger.error( "初始化缓存提供者发生异常:{}", e);
} finally {
providerLock.unlock();
}
return _listCacheProvider;
}
/**
* 查询缓存
*
* @param key 缓存键 不可为空
**/
publicextends Object> T get( String key) { 
T obj = null;
//key = generateVerKey(key);//构造带版本的缓存键
for (CacheProviderService provider : getCacheProviders()) {
obj = provider.get(key);
if (obj != null) {
return obj;
}
}
return obj;
}
/**
* 查询缓存
*
* @param key 缓存键 不可为空
* @param function 如没有缓存,调用该callable函数返回对象 可为空
**/
publicextends Object> T get( String key, Function< String, T> function) { 
T obj = null;
for (CacheProviderService provider : getCacheProviders()) {
if (obj == null) {
obj = provider.get(key, function);
} else if ( function != null && obj != null) { //查询并设置其他缓存提供者程序缓存
provider.get(key, function);
}
//如果callable函数为空 而缓存对象不为空 及时跳出循环并返回
if ( function == null && obj != null) {
return obj;
}
}
return obj;
}
/**
* 查询缓存
*
* @param key 缓存键 不可为空
* @param function 如没有缓存,调用该callable函数返回对象 可为空
* @param funcParm function函数的调用参数
**/
publicextends Object, M extends Object> T get( String key, Function function, M funcParm) { 
T obj = null;
for (CacheProviderService provider : getCacheProviders()) {
if (obj == null) {
obj = provider.get(key, function, funcParm);
} else if ( function != null && obj != null) { //查询并设置其他缓存提供者程序缓存
provider.get(key, function, funcParm);
}
//如果callable函数为空 而缓存对象不为空 及时跳出循环并返回
if ( function == null && obj != null) {
return obj;
}
}
return obj;
}
/**
* 查询缓存
*
* @param key 缓存键 不可为空
* @param function 如没有缓存,调用该callable函数返回对象 可为空
* @param expireTime 过期时间(单位:毫秒) 可为空
**/
publicextends Object> T get( String key, Function< String, T> function, long expireTime) { 
T obj = null;
for (CacheProviderService provider : getCacheProviders()) {
if (obj == null) {
obj = provider.get(key, function, expireTime);
} else if ( function != null && obj != null) { //查询并设置其他缓存提供者程序缓存
provider.get(key, function, expireTime);
}
//如果callable函数为空 而缓存对象不为空 及时跳出循环并返回
if ( function == null && obj != null) {
return obj;
}
}
return obj;
}
/**
* 查询缓存
*
* @param key 缓存键 不可为空
* @param function 如没有缓存,调用该callable函数返回对象 可为空
* @param funcParm function函数的调用参数
* @param expireTime 过期时间(单位:毫秒) 可为空
**/
publicextends Object, M extends Object> T get( String key, Function function, M funcParm, long expireTime) { 
T obj = null;
for (CacheProviderService provider : getCacheProviders()) {
if (obj == null) {
obj = provider.get(key, function, funcParm, expireTime);
} else if ( function != null && obj != null) { //查询并设置其他缓存提供者程序缓存
provider.get(key, function, funcParm, expireTime);
}
//如果callable函数为空 而缓存对象不为空 及时跳出循环并返回
if ( function == null && obj != null) {
return obj;
}
}
return obj;
}
/**
* 设置缓存键值 直接向缓存中插入或覆盖值
*
* @param key 缓存键 不可为空
* @param obj 缓存值 不可为空
**/
publicextends Object> void set( String key, T obj) { 
//key = generateVerKey(key);//构造带版本的缓存键
for (CacheProviderService provider : getCacheProviders()) {
provider.set(key, obj);
}
}
/**
* 设置缓存键值 直接向缓存中插入或覆盖值
*
* @param key 缓存键 不可为空
* @param obj 缓存值 不可为空
* @param expireTime 过期时间(单位:毫秒) 可为空
**/
publicextends Object> void set( String key, T obj, Long expireTime) { 
//key = generateVerKey(key);//构造带版本的缓存键
for (CacheProviderService provider : getCacheProviders()) {
provider.set(key, obj, expireTime);
}
}
/**
* 移除缓存
*
* @param key 缓存键 不可为空
**/
public void remove( String key) {
//key = generateVerKey(key);//构造带版本的缓存键
if (StringUtils.isEmpty(key) == true) {
return;
}
for (CacheProviderService provider : getCacheProviders()) {
provider.remove(key);
}
}
/**
* 是否存在缓存
*
* @param key 缓存键 不可为空
**/
public boolean contains( String key) {
boolean exists = false;
//key = generateVerKey(key);//构造带版本的缓存键
if (StringUtils.isEmpty(key) == true) {
return exists;
}
Object obj = get(key);
if (obj != null) {
exists = true;
}
return exists;
}
/**
* 获取分布式缓存版本号
**/
public String getCacheVersion() {
String version = "";
boolean isUseCache = checkUseRedisCache();
//未启用Redis缓存
if (isUseCache == false) {
return version;
}
version = redisCacheService.get(AppConst.CACHE_VERSION_KEY);
return version;
}
/**
* 重置分布式缓存版本 如果启用分布式缓存,设置缓存版本
**/
public String resetCacheVersion() {
String version = "";
boolean isUseCache = checkUseRedisCache();
//未启用Redis缓存
if (isUseCache == false) {
return version;
}
//设置缓存版本
version = String.valueOf( Math.abs(UUID.randomUUID().hashCode()));
redisCacheService.set(AppConst.CACHE_VERSION_KEY, version);
return version;
}
/**
* 如果启用分布式缓存,获取缓存版本,重置查询的缓存key,可以实现相对实时的缓存过期控制
*
* 如没有启用分布式缓存,缓存key不做修改,直接返回
**/
public String generateVerKey(String key) {
String result = key;
if (StringUtils.isEmpty(key) == true) {
return result;
}
boolean isUseCache = checkUseRedisCache();
//没有启用分布式缓存,缓存key不做修改,直接返回
if (isUseCache == false) {
return result;
}
String version = redisCacheService.get(AppConst.CACHE_VERSION_KEY);
if (StringUtils.isEmpty(version) == true) {
return result;
}
result = String.format("%s_%s", result, version);
return result;
}
/**
* 验证是否启用分布式缓存
**/
private boolean checkUseRedisCache() {
boolean isUseCache = false;
String strIsUseCache = ConfigUtil.getConfigVal(AppField.IS_USE_REDIS_CACHE);
isUseCache = "1".equalsIgnoreCase(strIsUseCache);
return isUseCache;
}
}
@Test
public void testCacheVerson() throws Exception {
        String version = cacheBuilder.getCacheVersion();
        System.out.println(String.format("当前缓存版本:%s", version));
        String cacheKey = cacheBuilder.generateVerKey("goods778899");
        GoodsVO goodsVO = new GoodsVO();
        goodsVO.setGoodsId(UUID.randomUUID().toString());
        goodsVO.setCreateTime(new Date());
        goodsVO.setCreateDate(new DateTime(new Date()));
        goodsVO.setGoodsType(1024);
        goodsVO.setGoodsCode("123456789");
        goodsVO.setGoodsName("我的测试商品");
        cacheBuilder.set(cacheKey, goodsVO);
        GoodsVO goodsVO1 = cacheBuilder.get(cacheKey);
        Assert.assertNotNull(goodsVO1);
        version = cacheBuilder.resetCacheVersion();
        System.out.println(String.format("重置后的缓存版本:%s", version));
        cacheKey = cacheBuilder.generateVerKey("goods112233");
        cacheBuilder.set(cacheKey, goodsVO);
        GoodsVO goodsVO2 = cacheBuilder.get(cacheKey);
        Assert.assertNotNull(goodsVO2);
        Assert.assertTrue("两个缓存对象的主键相同", goodsVO1.getGoodsId().equals(goodsVO2.getGoodsId()));
    }
  String cacheKey = _cacheBuilder.generateVerKey("com.power.demo.apiservice.impl.getgoodsbyid." + request.getGoodsId());
GoodsVO goodsVO = _cacheBuilder.get(cacheKey, _goodsService::getGoodsByGoodsId, request.getGoodsId());
  参考:
http://ifeve.com/google-guava/ 
http://www.cnblogs.com/luochengqiuse/p/4640932.html
商城源码下载
商城管理后端演示图
源码地址获取方法,老规矩啦!
识别下方二维码,关注后回复【A107】
即可获取下载链接
