Redis和EhCache作为Spring的缓存

Redis和EhCache作为Spring的缓存

Posted by wenfengSAT on April 3, 2018

EhCache作为缓存配置 :

依赖

“org.ehcache:ehcache:3.1.0”,

JavaConfig配置



package com.github.izhangzhihao.SpringMVCSeedProject.Config;

import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

/**
 * 将SpringMVC缓存至EhCache中就取消注释该文件,注释掉
 * @see RedisCacheConfig
 */
@EnableCaching
@Configuration
public class EhCacheConfig {

    @Bean
    public EhCacheManagerFactoryBean getEhcache() {
        EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
        ehCacheManagerFactoryBean.setShared(true);
        ehCacheManagerFactoryBean.setAcceptExisting(true);
        Resource resource = new ClassPathResource("ehcache.xml");
        ehCacheManagerFactoryBean.setConfigLocation(resource);
        return ehCacheManagerFactoryBean;
    }

    @Bean
    public EhCacheCacheManager getEhCacheCacheManager() {
        EhCacheCacheManager ehCacheCacheManager = new EhCacheCacheManager();
        ehCacheCacheManager.setCacheManager(getEhcache().getObject());
        return ehCacheCacheManager;
    }

}



XML配置



<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cache="http://www.springframework.org/schema/cache" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/cache
                            http://www.springframework.org/schema/cache/spring-cache.xsd">

    <!--配置ehcache-->
    <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
          p:shared="true"
          p:acceptExisting="true"
          p:configLocation="classpath:ehcache.xml"/>

    <!--配置缓存管理器-->
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
          p:cacheManager-ref="ehcache"/>

    <!--启用缓存注解 注解方式配置@EnableCaching-->
    <cache:annotation-driven cache-manager="cacheManager"/>

</beans>



Redis作为缓存配置 :

依赖

“org.springframework.data:spring-data-redis:1.7.2.RELEASE”, “redis.clients:jedis:2.9.0”, “org.apache.commons:commons-pool2:2.4.2”,

JavaConfig配置

RedisConfig



@Configuration
@EnableRedisHttpSession
@PropertySource("classpath:redis.properties") //导入资源文件
public class RedisConfig {

    @Value("${redis.host}")
    String host;
    @Value("${redis.port}")
    int port;
    @Value("${redis.timeout}")
    int timeout;
    @Value("${redis.database}")
    int database;
    @Value("${redis.maxTotal}")
    int maxTotal;
    @Value("${redis.maxIdle}")
    int maxIdle;
    @Value("${redis.maxWaitMillis}")
    int maxWaitMillis;
    @Value("${redis.testOnBorrow}")
    boolean testOnBorrow;

    @Bean
    public JedisPoolConfig getJedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(maxTotal);
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
        jedisPoolConfig.setTestOnBorrow(testOnBorrow);
        return jedisPoolConfig;
    }

    @Bean
    public JedisConnectionFactory getConnectionFactory() {
        JedisConnectionFactory connection = new JedisConnectionFactory();
        connection.setHostName(host);
        connection.setPort(port);
        connection.setTimeout(timeout);
        connection.setDatabase(database);
        connection.setPoolConfig(getJedisPoolConfig());
        return connection;
    }

    @Bean
    public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }
}


RedisCacheConfig



@Configuration
@EnableCaching
public class RedisCacheConfig extends CachingConfigurerSupport {

    /**
     * 缓存管理器
     */
    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
        cacheManager.setDefaultExpiration(300);// 设置缓存过期时间单位秒,默认不过期
        return cacheManager;
    }

    /**
     * @return 自定义策略生成的key
     * 自定义的缓存key的生成策略</br>
     * 若想使用这个key</br>
     * 只需要讲注解上keyGenerator的值设置为customKeyGenerator即可</br>
     */
    @Bean
    public KeyGenerator customKeyGenerator() {
        return (o, method, objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(o.getClass().getName());
            sb.append(method.getName());
            for (Object obj : objects) {
				sb.append("-");
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }
}


XML配置

Spring-Redis.xml



<?xml version="1.0" encoding="UTF-8"?>
<!--suppress SpringPlaceholdersInspection -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:redis="http://www.springframework.org/schema/redis"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/redis
		http://www.springframework.org/schema/redis/spring-redis.xsd ">

    <description>Redis配置</description>
    <!-- 导入资源文件 -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:redis.properties</value>
            </list>
        </property>
        <property name="ignoreUnresolvablePlaceholders" value="true" />
    </bean>

    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"
          p:maxIdle="${redis.maxIdle}"
          p:maxTotal="${redis.maxTotal}"
          p:maxWaitMillis="${redis.maxWaitMillis}"
          p:testOnBorrow="${redis.testOnBorrow}"/>

    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          p:hostName="${redis.host}"
          p:port="${redis.port}"
          p:password="${redis.passWord}"
          p:timeout="${redis.timeout}"
          p:database="${redis.database}"
          p:poolConfig-ref="poolConfig"/>

    <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <property name="valueSerializer" ref="redisSerializer"/>
        <property name="keySerializer" ref="stringSerializer" />
        <!--<property name="enableTransactionSupport" value="true" />-->
    </bean>

    <bean id="stringSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    <bean id="redisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>

</beans>


Spring-RedisCache.xml



<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans.xsd
                            http://www.springframework.org/schema/cache
                            http://www.springframework.org/schema/cache/spring-cache.xsd">

    <!--配置缓存管理器-->
    <bean id="cacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
        <constructor-arg name="redisOperations" ref="redisTemplate"/>
        <property name="defaultExpiration" value="300"/><!--设置缓存过期时间单位秒,默认不过期-->
    </bean>

    <!--启用缓存注解 注解方式配置@EnableCaching-->
    <cache:annotation-driven cache-manager="cacheManager"/>

</beans>


缓存指定方法的执行结果

设置好缓存配置之后我们就可以使用 @Cacheable 注解来缓存方法执行的结果了



@RestController
@RequestMapping("/Log")
public class LogController {
    /**
     * 日志分页查询
     *
     * @param pageNumber 页码
     * @param pageSize   每页大小
     * @return json数据
     */
    @GetMapping("/getLogByPage/pageNumber/{pageNumber}/pageSize/{pageSize}")
    @Cacheable("getLogByPage")
    public PageResults<Log> getLogByPage(@PathVariable int pageNumber,
                                         @PathVariable int pageSize) throws Exception {
        return logService.getListByPage(pageNumber, pageSize);
    }
}


缓存一致性保证

CRUD (Create 创建,Read 读取,Update 更新,Delete 删除) 操作中,除了 R 具备幂等性,其他三个都可能会造成缓存结果和数据库不一致。 为了保证缓存数据的一致性,在进行 CUD 操作的时候我们需要对可能影响到的缓存进行更新或者清除。 使用 @CacheEvict 清除缓存。如果 CUD 相关方法能返回实体,也可以使用 @CachePut 更新缓存策略。 @CacheEvict会将所有相关方法的缓存都清理掉,所以能用@CachePut的话最好。

自定义缓存 key 生成策略

对于使用 @Cacheable 注解的方法,每个缓存的 key 生成策略默认使用的是参数名+参数值, 这个方法的缓存将保存于 key 为例如 getLogByPage~keys 的缓存下,但是@Cacheable(value=”XXX”),如果”XXX”重复的话, 两个方法之间的缓存就会互相覆盖,出现问题。

解决办法是使用自定义缓存策略:见上面的customKeyGenerator()方法。 使用方式@Cacheable(value = “getLogByPage”, keyGenerator = “customKeyGenerator”)。 这样生成的key就变成了com.github.izhangzhihao.SpringMVCSeedProject.Controller.LogControllergetLogByPage110这样的

注意:

要缓存的 Java 对象必须实现 Serializable 接口