Spring Boot 整合 RedisCache,EhCache,GuavaCache实战

https://www.jianshu.com/p/a98796caf536

1. Spring 的Cache框架

      整合 不是分别整合几种缓存,而是同时使用多种缓存。根据项目中不同的缓存需求采用不同的缓存技术。

1.1 一次聊天

前些日子和朋友聊天时,他们项目中用到缓存,聊天中了解到,他们的缓存采用的是自己写的一个叫ICache的接口。缓存有redis缓存 和 OCS缓存(并不知道他们这个是什么鬼)。

看了他们接口API,基本和 spring的cache 框架一样。

其实他们也可以使用spring cache ,只需要编写一个OCSCache和 OCSCacheManager就行了。

一般项目中用缓存都是单一使用的,像朋友这样用好几种的不太多。其实spring cache 是支持多种缓存混合使用。

下面就是怎么利用spring cache 实现多种缓存技术的混合使用的。

1.2 Cache 和 CacheManager

spring 通过 cache 和 cacheManager 整合 和 管理不同缓存技术,通过 对应的CacheManager 管理 Cache,

比如 redis 、guava、ehcache、Jcache、还有自定义的cache。

org.springframework.cache.Cache

org.springframework.cache.CacheManager

1.3 缓存注解

Spring Cache 十分强大,在使用缓存时,对项目几乎没有侵入,使用时

只需要在需要使用的方法上面加上对应的注解,并且配合强大的SPEL,就可以很简单的使用各种缓存啦。以后切换缓存也是很方便。注解怎么使用可以参考其他的关于这方便的介绍。

@Cacheable 查询缓存

@CacheEvict 删除缓存条目

@CachePut 更新缓存条目

@Caching

@CacheConfig

@EnableCaching 启用Spring Cache

1.4 CacheMangager

       CacheManager简单描述就是用来存放Cache,Cache用于存放具体的key-value值。举个栗子:一个班级管理员 可以根据名字找到对应的学生,那么cacheManager 也是如此,CacheManager 负责缓存的创建和管理。常见的有下面集中。

RedisCacheManager 管理redis缓存

GuavaCacheManager 谷歌的guava缓存

EhchcheManager EhCache 管理

CompositeCacheManager 混合的缓存管理(可以同时使用多种缓存)

2. SpringBoot整合多种缓存

有时候在项目中会用到多种缓存同时使用的情况,就需要通过Spring提供的CompositeCacheManager来整合多种缓冲,通过缓存名字来指定使用的缓存。恕我语言匮乏,实在不知道该怎么说,只能贴代码了。有耐心的看下代码,就知道怎么做了。不懂的可以留言问我。

2.1 引入jar

<!-- spring-cache -->org.springframework.bootspring-boot-starter-cache<!-- 谷歌的guava cache -->com.google.guavaguava23.3-jre<!-- redis -->org.springframework.bootspring-boot-starter-data-redis<!-- EhCache -->net.sf.ehcacheehcache

2.2 配置文件

application.properties:

# redis配置spring.redis.host=localhost spring.redis.port=6379spring.redis.pool.max-idle=8spring.redis.pool.max-wait=-1spring.redis.pool.max-active=8# 指定ehcahce 配置文件路径spring.cache.ehcache.config=cache/ehcache.xmlspring.redis.database=0

ehcache.xml EhCachede配置文件,其实不想用XML.

<?xml version="1.0"encoding="UTF-8"?><!-- diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。

    参数解释如下: user.home – 用户主目录

    user.dir – 用户当前工作目录

    java.io.tmpdir – 默认临时文件路径 --><!-- defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。 --><!-- name:缓存名称。

        maxElementsInMemory:缓存最大数目

        maxElementsOnDisk:硬盘最大缓存个数。

        eternal:对象是否永久有效,一但设置了,timeout将不起作用。

        overflowToDisk:是否保存到磁盘,当系统当机时

        timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使 用,可选属性,默认值是0,也就是可闲置时间无穷大。

        timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅 当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。

        diskPersistent:是否缓存虚拟机重启期数据Whether the disk store persists between restarts

        of the Virtual Machine. The default value is false.

        diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该 有自己的一个缓冲区。

        diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。

        memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内 存。默认策略是LRU(最近最少使用)。

        你可以设置为FIFO(先进先出)或是LFU(较少使用)。

        clearOnFlush:内存数量最大时是否清除。

        memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少 访问次数)。

        FIFO,first in first out,这个是大家最熟的,先进先出。

        LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面 所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。

        LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地 方来缓存新的元素的时候,

        那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。 -->

RedisConfig Redis配置 这个很简洁

packagecom.example.demo.config;importorg.apache.log4j.Logger;importorg.springframework.boot.context.properties.ConfigurationProperties;importorg.springframework.cache.annotation.CachingConfigurerSupport;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.data.redis.connection.jedis.JedisConnectionFactory;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.core.StringRedisTemplate;importorg.springframework.data.redis.serializer.StringRedisSerializer;importredis.clients.jedis.JedisPoolConfig;/**

*redis 配置

*/@ConfigurationpublicclassRedisConfigextendsCachingConfigurerSupport{privatestaticLogger logger = Logger.getLogger(RedisConfig.class);@Bean@ConfigurationProperties(prefix="spring.redis")publicJedisPoolConfiggetRedisConfig(){        JedisPoolConfig config =newJedisPoolConfig();returnconfig;    }@BeanpublicJedisConnectionFactorygetConnectionFactory(RedisProperties redisProperties){        JedisConnectionFactory factory =newJedisConnectionFactory();        JedisPoolConfig config = getRedisConfig();        factory.setDatabase(redisProperties.getDatabase());        factory.setHostName(redisProperties.getHost());        factory.setPassword(redisProperties.getPassword());        factory.setPort(redisProperties.getPort());        factory.setPoolConfig(config);        logger.info("JedisConnectionFactory bean init success.");returnfactory;    }@BeanpublicStringRedisTemplategetRedisTemplate( RedisProperties redisProperties){        JedisConnectionFactory connectionFactory = getConnectionFactory(redisProperties);        StringRedisTemplate template =newStringRedisTemplate(connectionFactory);//设置redis 序列化template.setStringSerializer(newStringRedisSerializer());returntemplate;    }}

CacheConfig.java 这个缓存的配置

packagecom.example.demo.config;importcom.example.demo.constant.CacheConstant;importcom.google.common.cache.CacheBuilder;importcom.google.common.collect.Lists;importnet.sf.ehcache.config.CacheConfiguration;importnet.sf.ehcache.store.MemoryStoreEvictionPolicy;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.cache.CacheManager;importorg.springframework.cache.annotation.EnableCaching;importorg.springframework.cache.ehcache.EhCacheCacheManager;importorg.springframework.cache.ehcache.EhCacheManagerFactoryBean;importorg.springframework.cache.guava.GuavaCacheManager;importorg.springframework.cache.support.CompositeCacheManager;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.core.io.ClassPathResource;importorg.springframework.data.redis.cache.DefaultRedisCachePrefix;importorg.springframework.data.redis.cache.RedisCacheManager;importorg.springframework.data.redis.core.RedisTemplate;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.TimeUnit;/** *@authorhuxingnan *@date2018/4/11 14:05 */@Configuration// 自动配置@EnableCaching//启用Spring cachepublicclassCacheConfig{// 注释掉的 是我自己 分别配置几种缓存的时候用的 spring ioc 中只能有一个 CacheManager 实列,如果 有多个会报错。    //@Bean//    public CacheManager guavaCacheManager() {//        GuavaCacheManager cacheManager = new GuavaCacheManager();//        cacheManager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterWrite(3600, TimeUnit.SECONDS).maximumSize(1000));//        return cacheManager;//    }    @Bean//    public CacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) {//        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);//        return redisCacheManager;//    }@Value("${spring.cache.ehcache.config}")privateString ehCacheCongifPath;/**    *@return*/@BeanpublicEhCacheManagerFactoryBeanehCacheManagerFactoryBean(){        EhCacheManagerFactoryBean cacheManagerFactoryBean =newEhCacheManagerFactoryBean();        System.out.println(ehCacheCongifPath);        cacheManagerFactoryBean.setConfigLocation(newClassPathResource(ehCacheCongifPath));        cacheManagerFactoryBean.setShared(true);//如果 Factory 自己手动实列化,需要 执行afterPropertiesSet()方法,因为这是方法是 初始化 类使用的//如果Factory 由Spring 容器 创建 ,容器初始化完成后 spring 会去执行这个方法。//        cacheManagerFactoryBean.afterPropertiesSet();//初始化 读取配置文件,returncacheManagerFactoryBean;    }/**    * 混合缓存管理    *    *@paramredisTemplate redis template    *@returncacheManager    */@BeanpublicCacheManagercompositeCacheManager(@Autowired RedisTemplate<Object, Object> redisTemplate, @Autowired EhCacheManagerFactoryBean factoryBean){        RedisCacheManager redisCacheManager = getRedisCacheManager(redisTemplate);        GuavaCacheManager guavaCacheManager = getGuavaCacheManager();        EhCacheCacheManager ehCacheCacheManager = ehCacheCacheManager(factoryBean);        CompositeCacheManager cacheManager =newCompositeCacheManager(redisCacheManager, guavaCacheManager, ehCacheCacheManager);        cacheManager.setFallbackToNoOpCache(true);        cacheManager.afterPropertiesSet();returncacheManager;    }/**    * 获取guava 实列的缓存    *    *@returnguava缓存管理 实列    */privateGuavaCacheManagergetGuavaCacheManager(){        GuavaCacheManager guavaCacheManager =newGuavaCacheManager();        guavaCacheManager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterWrite(3600, TimeUnit.SECONDS).maximumSize(1000));        ArrayList guavaCacheNames = Lists.newArrayList();        guavaCacheNames.add(CacheConstant.GUAVA_CACHE_A);        guavaCacheManager.setCacheNames(guavaCacheNames);returnguavaCacheManager;    }/**    * 获取redisCacheManager    *    *@paramredisTemplate redisTemplate    *@returnredisCacheManager    */privateRedisCacheManagergetRedisCacheManager(RedisTemplate<Object, Object> redisTemplate){        RedisCacheManager redisCacheManager =newRedisCacheManager(redisTemplate);        List redisCacheNames = Lists.newArrayList();        redisCacheNames.add(CacheConstant.REDIS_CACHE_A);//一个cacheName 对应一个 缓存实列redisCacheNames.add(CacheConstant.REDIS_CACHE_B);        redisCacheManager.setCacheNames(redisCacheNames);//redis key 前缀redisCacheManager.setCachePrefix(newDefaultRedisCachePrefix("demo"));//缓存key 前缀redisCacheManager.setUsePrefix(true);//使用前缀redisCacheManager.initializeCaches();//rediscache 需要初始化 缓存returnredisCacheManager;    }/**    * EhCacheManager    *    *@returnEhCacheManager    */privateEhCacheCacheManagerehCacheCacheManager(EhCacheManagerFactoryBean factoryBean){        EhCacheCacheManager ehCacheCacheManager =newEhCacheCacheManager(factoryBean.getObject());//由于自己实列化EhCacheManager 需要执行 手动初始化 方法。ehCacheCacheManager.initializeCaches();//初始化returnehCacheCacheManager;    }}

2.3 怎么用

测试对象Account

@Data@AllArgsConstructor@NoArgsConstructorpublicclassAccount{privateString id;privateString userName;privateString passWord;@DateTimeFormat(pattern ="yyy-MM-dd")privateDate createTime;privateString alias;privateInteger level;privateBoolean vip;}

AccountService

/** *@authorhuxingnan *@date2018/4/12 13:17 */@ServicepublicclassAccountServiceImplimplementsAccountService{@Override@CachePut(value = CacheConstant.EHCACHE_A,key ="#account.id")publicAccountsaveAccount(Account account){        System.out.println("保存成功"+account);        account.setId("999");        account.setCreateTime(newDate());returnaccount;    }@Override@Cacheable(value = CacheConstant.EHCACHE_A,key ="#account.id")publicAccountgetAccountById(Account account){        Account account1 =newAccount(account.getId(),"zhangfei","zf12345",newDate(),"张飞",2,false);returnaccount1;    }@Override@Cacheable(value = CacheConstant.EHCACHE_A,key="#account.userName")publicListgetAccountList(Account account){        List accountList = Lists.newArrayList();        accountList.add(newAccount("124","zhaoyun","zy9999",newDate(),"赵云",3,true));        accountList.add(newAccount("125","lvbu","zy9999",newDate(),"吕布",3,true));        System.out.println("查询accountList"+account);returnaccountList;    }@Override@CacheEvict(value = CacheConstant.EHCACHE_A,key="#account.id")publicintdeleteAccountById(Account account){        System.out.println("删除account"+account);return1;    }@Override@CacheEvict(value = CacheConstant.EHCACHE_A,key ="#p0.id")publicintupdateAccountById(Account account){        System.out.println("更新account"+account);return1;    }}

作者:白袜子先生

链接:https://www.jianshu.com/p/a98796caf536

來源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值