继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

Spring Boot 整合 RedisCache,EhCache,GuavaCache实战

largeQ
关注TA
已关注
手记 994
粉丝 93
获赞 586

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 --><dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId></dependency><!-- 谷歌的guava cache --><dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>23.3-jre</version></dependency><!-- redis --><dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId></dependency>   <!-- EhCache --><dependency>
    <groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId></dependency>

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.xml
spring.redis.database=0
  • ehcache.xml EhCachede配置文件,其实不想用XML.

<?xml version="1.0" encoding="UTF-8"?><ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!-- diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。
    参数解释如下: user.home – 用户主目录
    user.dir – 用户当前工作目录
    java.io.tmpdir – 默认临时文件路径 -->
    <diskStore path="java.io.tmpdir/Tmp_EhCache" />
    <!-- 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,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地 方来缓存新的元素的时候,
         那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。 -->
    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
                  timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" />
    <cache name="EhcacheA" eternal="false" maxElementsInMemory="10000" overflowToDisk="false" diskPersistent="false"
           timeToIdleSeconds="0" timeToLiveSeconds="0" memoryStoreEvictionPolicy="LFU" /></ehcache>
  • RedisConfig Redis配置 这个很简洁

package com.example.demo.config;import org.apache.log4j.Logger;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.cache.annotation.CachingConfigurerSupport;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.data.redis.serializer.StringRedisSerializer;import redis.clients.jedis.JedisPoolConfig;/**
 *redis 配置
 */@Configurationpublic class RedisConfig extends CachingConfigurerSupport {    private static Logger logger = Logger.getLogger(RedisConfig.class);    @Bean
    @ConfigurationProperties(prefix="spring.redis")    public JedisPoolConfig getRedisConfig(){
        JedisPoolConfig config = new JedisPoolConfig();        return config;
    }    @Bean
    @ConfigurationProperties(prefix="spring.redis")    public JedisConnectionFactory getConnectionFactory(){
        JedisConnectionFactory factory = new JedisConnectionFactory();
        JedisPoolConfig config = getRedisConfig();
        factory.setPoolConfig(config);
        logger.info("JedisConnectionFactory bean init success.");        return factory;
    }    @Bean
    public RedisTemplate<?, ?> getRedisTemplate(){
        RedisTemplate<?,?> template = new StringRedisTemplate(getConnectionFactory());
        template.setStringSerializer(new StringRedisSerializer());//设置redis 序列化 
        return template;
    }

}
  • CacheConfig.java 这个缓存的配置

package com.example.demo.config;import com.example.demo.constant.CacheConstant;import com.google.common.cache.CacheBuilder;import com.google.common.collect.Lists;import net.sf.ehcache.config.CacheConfiguration;import net.sf.ehcache.store.MemoryStoreEvictionPolicy;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.cache.CacheManager;import org.springframework.cache.annotation.EnableCaching;import org.springframework.cache.ehcache.EhCacheCacheManager;import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;import org.springframework.cache.guava.GuavaCacheManager;import org.springframework.cache.support.CompositeCacheManager;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.ClassPathResource;import org.springframework.data.redis.cache.DefaultRedisCachePrefix;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.core.RedisTemplate;import java.util.ArrayList;import java.util.List;import java.util.concurrent.TimeUnit;/**
 * @author huxingnan
 * @date 2018/4/11 14:05
 */@Configuration // 自动配置@EnableCaching //启用Spring cachepublic class CacheConfig {    // 注释掉的 是我自己 分别配置几种缓存的时候用的 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}")    private String ehCacheCongifPath;    /**
     * @return
     */
    @Bean
    public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() {
        EhCacheManagerFactoryBean cacheManagerFactoryBean = new EhCacheManagerFactoryBean();
        System.out.println(ehCacheCongifPath);
        cacheManagerFactoryBean.setConfigLocation(new ClassPathResource(ehCacheCongifPath));
        cacheManagerFactoryBean.setShared(true);        //如果 Factory 自己手动实列化,需要 执行afterPropertiesSet()方法,因为这是方法是 初始化 类使用的
        //如果Factory 由Spring 容器 创建 ,容器初始化完成后 spring 会去执行这个方法。//        cacheManagerFactoryBean.afterPropertiesSet();//初始化 读取配置文件,

        return cacheManagerFactoryBean;
    }    /**
     * 混合缓存管理
     *
     * @param redisTemplate redis template
     * @return cacheManager
     */
    @Bean
    public CacheManager compositeCacheManager(@Autowired RedisTemplate<Object, Object> redisTemplate, @Autowired EhCacheManagerFactoryBean factoryBean) {
        RedisCacheManager redisCacheManager = getRedisCacheManager(redisTemplate);
        GuavaCacheManager guavaCacheManager = getGuavaCacheManager();
        EhCacheCacheManager ehCacheCacheManager = ehCacheCacheManager(factoryBean);
        CompositeCacheManager cacheManager = new CompositeCacheManager(redisCacheManager, guavaCacheManager, ehCacheCacheManager);
        cacheManager.setFallbackToNoOpCache(true);
        cacheManager.afterPropertiesSet();        return cacheManager;
    }    /**
     * 获取guava 实列的缓存
     *
     * @return guava缓存管理 实列
     */
    private GuavaCacheManager getGuavaCacheManager() {
        GuavaCacheManager guavaCacheManager = new GuavaCacheManager();
        guavaCacheManager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterWrite(3600, TimeUnit.SECONDS).maximumSize(1000));
        ArrayList<String> guavaCacheNames = Lists.newArrayList();
        guavaCacheNames.add(CacheConstant.GUAVA_CACHE_A);
        guavaCacheManager.setCacheNames(guavaCacheNames);        return guavaCacheManager;
    }    /**
     * 获取redisCacheManager
     *
     * @param redisTemplate redisTemplate
     * @return redisCacheManager
     */
    private RedisCacheManager getRedisCacheManager(RedisTemplate<Object, Object> redisTemplate) {
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
        List<String> redisCacheNames = Lists.newArrayList();
        redisCacheNames.add(CacheConstant.REDIS_CACHE_A);//一个cacheName 对应一个 缓存实列
        redisCacheNames.add(CacheConstant.REDIS_CACHE_B);
        redisCacheManager.setCacheNames(redisCacheNames);        //redis key 前缀
        redisCacheManager.setCachePrefix(new DefaultRedisCachePrefix("demo"));//缓存key 前缀
        redisCacheManager.setUsePrefix(true);//使用前缀
        redisCacheManager.initializeCaches();//rediscache 需要初始化 缓存
        return redisCacheManager;
    }    /**
     * EhCacheManager
     *
     * @return EhCacheManager
     */
    private EhCacheCacheManager ehCacheCacheManager(EhCacheManagerFactoryBean factoryBean) {
        EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager(factoryBean.getObject());        //由于自己实列化EhCacheManager 需要执行 手动初始化 方法。
        ehCacheCacheManager.initializeCaches();//初始化
        return ehCacheCacheManager;
    }


}

2.3 怎么用

  • 测试对象Account

@Data@AllArgsConstructor@NoArgsConstructorpublic class Account {    private String id;    private String userName;    private String passWord;    @DateTimeFormat(pattern = "yyy-MM-dd")    private Date createTime;    private String alias;    private Integer level;    private Boolean vip;
}
  • AccountService

/**
 * @author huxingnan
 * @date 2018/4/12 13:17
 */@Servicepublic class AccountServiceImpl implements AccountService {    @Override
    @CachePut(value = CacheConstant.EHCACHE_A,key = "#account.id")    public Account saveAccount(Account account) {

        System.out.println("保存成功"+account);
        account.setId("999");
        account.setCreateTime(new Date());        return account;
    }    @Override
    @Cacheable(value = CacheConstant.EHCACHE_A,key = "#account.id")    public Account getAccountById(Account account) {
        Account account1 = new Account(account.getId(),"zhangfei","zf12345",new Date(),"张飞",2,false);        return account1;
    }    @Override
    @Cacheable(value = CacheConstant.EHCACHE_A,key="#account.userName")    public List<Account> getAccountList(Account account) {
        List<Account> accountList = Lists.newArrayList();
        accountList.add(new Account("124","zhaoyun","zy9999",new Date(),"赵云",3,true));
        accountList.add(new Account("125","lvbu","zy9999",new Date(),"吕布",3,true));
        System.out.println("查询accountList"+account);        return accountList;
    }    @Override
    @CacheEvict(value = CacheConstant.EHCACHE_A,key="#account.id")    public int deleteAccountById(Account account) {
        System.out.println("删除account"+account);        return 1;
    }    @Override
    @CacheEvict(value = CacheConstant.EHCACHE_A,key = "#p0.id")    public int updateAccountById(Account account) {
        System.out.println("更新account"+account);        return 1;
    }
}



作者:白袜子先生
链接:https://www.jianshu.com/p/a98796caf536


打开App,阅读手记
2人推荐
发表评论
随时随地看视频慕课网APP