Spring Boot 整合 RedisCache,EhCache,GuavaCache实战

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



    org.springframework.boot
    spring-boot-starter-cache



    com.google.guava
    guava
    23.3-jre



    org.springframework.boot
    spring-boot-starter-data-redis
   


    net.sf.ehcache
    ehcache

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.


    
    
    
    
    
    

  • 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
    public JedisConnectionFactory getConnectionFactory(RedisProperties redisProperties){
        JedisConnectionFactory factory = new JedisConnectionFactory();
        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.");
        return factory;
    }


    @Bean
    public StringRedisTemplate getRedisTemplate( RedisProperties redisProperties){
        JedisConnectionFactory connectionFactory = getConnectionFactory(redisProperties);
        StringRedisTemplate template = new StringRedisTemplate(connectionFactory);
        //设置redis 序列化
        template.setStringSerializer(new StringRedisSerializer());
        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 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 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 guavaCacheNames = Lists.newArrayList();
        guavaCacheNames.add(CacheConstant.GUAVA_CACHE_A);
        guavaCacheManager.setCacheNames(guavaCacheNames);
        return guavaCacheManager;
    }

    /**
     * 获取redisCacheManager
     *
     * @param redisTemplate redisTemplate
     * @return redisCacheManager
     */
    private RedisCacheManager getRedisCacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager redisCacheManager = new RedisCacheManager(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(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 getAccountList(Account account) {
        List 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,EhCache,GuavaCache实战)