美文网首页Spring-BootSpring Boot我爱编程
Spring Boot 整合 RedisCache,EhCach

Spring Boot 整合 RedisCache,EhCach

作者: 白袜子先生 | 来源:发表于2018-04-14 15:59 被阅读446次

    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=6379
    spring.redis.pool.max-idle=8
    spring.redis.pool.max-wait=-1
    spring.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 配置
     */
    @Configuration
    public 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 cache
    public 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
    @NoArgsConstructor
    public 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
     */
    @Service
    public 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;
        }
    }
    
    

    相关文章

      网友评论

      本文标题:Spring Boot 整合 RedisCache,EhCach

      本文链接:https://www.haomeiwen.com/subject/vwylkftx.html