SpringBoot中使用Redis實現緩存

Spring Data Redis爲咱們封裝了Redis客戶端的各類操做,簡化使用。java

  • 當Redis當作數據庫或者消息隊列來操做時,咱們通常使用RedisTemplate來操做
  • 當Redis做爲緩存使用時,咱們能夠將它做爲Spring Cache的實現,直接經過註解使用

關於RedisTemplate的使用可參考:blog.didispace.com/springbootr…redis

下面總結使用Redis做爲緩存

引入依賴

SpringBoot從1.4版本開始,spring-boot-starter-redis依賴更名了。spring

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>1.5.2.RELEASE</version>
</dependency>
複製代碼

配置文件

spring:
 redis:
 host: 127.0.0.1
 port: 6379
 timeout: 0
 database: 0
 pool:
 max-active: 8
 max-wait: -1
 max-idle: 8
 min-idle: 0
複製代碼

這樣,SpringBoot將會自動配置redis,注入相關bean,咱們就可使用@CacheConfig@Cacheable@CachePut@CacheEvict了。數據庫

使用Cache註解時的問題

緩存對象集合中,緩存是以key-value形式保存的。當不指定緩存的key時,SpringBoot會使用SimpleKeyGenerator生成key。數組

public class SimpleKeyGenerator implements KeyGenerator {

	@Override
	public Object generate(Object target, Method method, Object... params) {
		return generateKey(params);
	}

	/** * Generate a key based on the specified parameters. */
	public static Object generateKey(Object... params) {
		if (params.length == 0) {
			return SimpleKey.EMPTY;
		}
		if (params.length == 1) {
			Object param = params[0];
			if (param != null && !param.getClass().isArray()) {
				return param;
			}
		}
		return new SimpleKey(params);
	}
}
複製代碼
public SimpleKey(Object... elements) {
		Assert.notNull(elements, "Elements must not be null");
		this.params = new Object[elements.length];
		System.arraycopy(elements, 0, this.params, 0, elements.length);
		this.hashCode = Arrays.deepHashCode(this.params);
	}
複製代碼

查看源碼能夠發現,它是使用方法參數組合生成的一個key。 此時有一個問題: 若是2個方法,參數是同樣的,但執行邏輯不一樣,那麼將會致使執行第二個方法時命中第一個方法的緩存。 解決辦法是在@Cacheable註解參數中指定key,或者本身實現一個KeyGenerator,在註解中指定KeyGenerator。 可是若是這樣的狀況不少,每個都要指定key、KeyGenerator很麻煩。緩存

Spring一樣提供了方案:繼承CachingConfigurerSupport並重寫keyGenerator()springboot

下面貼出代碼:app

@EnableCaching
@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {

    @Autowired
    private JedisConnectionFactory jedisConnectionFactory;

    @Bean
    public RedisTemplate redisTemplate() {
        StringRedisTemplate redisTemplate = new StringRedisTemplate(jedisConnectionFactory);

        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    public CacheManager cacheManager() {
        String[] cacheNames = {"app_default", "users", "blogs", "goods", "configs", "info"};
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate(), Arrays.asList(cacheNames));
        redisCacheManager.setDefaultExpiration(86400);
        return redisCacheManager;
    }

    @Bean
    public Cache cache() {
        return cacheManager().getCache("app_default");
    }

    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return (target, method, objects) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append("::" + method.getName() + ":");
            for (Object obj : objects) {
                sb.append(obj.toString());
            }
            return sb.toString();
        };
    }
}
複製代碼

此時,緩存的key是包名+方法名+參數列表,這樣就很難會衝突了。ide

相關文章
相關標籤/搜索