Spring Boot In Practice (1):Redis 缓存实战

栏目: Java · 发布时间: 7年前

内容简介:Spring Boot In Practice (1):Redis 缓存实战

阅读本文需要对Spring和 Redis 比较熟悉。

Spring Framework 提供了Cache Abstraction对缓存层进行了抽象封装,通过几个annotation可以透明给您的应用增加缓存支持,而不用去关心底层缓存具体由谁实现。目前支持的缓存有 java.util.concurrent.ConcurrentMap ,Ehcache 2.x,Redis等。

一般我们使用最常用的Redis做为缓存实现(Spring Data Redis),

  • 需要引入的 starter : spring-boot-starter-data-redis , spring-boot-starter-cache ;
  • 自动配置生成的Beans: RedisConnectionFactory , StringRedisTemplate , RedisTemplate , RedisCacheManager ,自动配置的Bean可以直接注入我们的代码中使用;

I. 配置

application.properties

# REDIS (RedisProperties)
spring.redis.host=localhost # Redis server host.
spring.redis.port=6379 # Redis server port.
spring.redis.password= # Login password of the redis server.

具体对Redis cluster或者Sentinel的配置可以参考 这里

开启缓存支持

@SpringBootApplication
@EnableCaching//开启caching
public class NewsWebServer {
//省略内容
}

定制RedisTemplate

自动配置的 RedisTemplate 并不能满足大部分项目的需求,比如我们基本都需要设置特定的 Serializer (RedisTemplate默认会使用 JdkSerializationRedisSerializer )。

Redis底层中存储的数据只是字节。虽然Redis本身支持各种类型(List, Hash等),但在大多数情况下,这些指的是数据的存储方式,而不是它所代表的内容(内容都是byte)。用户自己来决定数据如何被转换成String或任何其他对象。用户(自定义)类型和原始数据类型之间的 互相转换 通过RedisSerializer接口(包org.springframework.data.redis.serializer)来处理,顾名思义,它负责处理序列化/反序列化过程。多个实现可以开箱即用,如:StringRedisSerializer和JdkSerializationRedisSerialize。Jackson2JsonRedisSerializer或GenericJackson2JsonRedisSerializer来处理JSON格式的数据。请注意,存储格式不仅限于value 它可以用于key,Hash的key和value。

声明自己的 RedisTemplate 覆盖掉自动配置的Bean:

//通用的RedisTemplate
@Bean
public RedisTemplate<String, Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory) {
    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(jedisConnectionFactory);
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    //template.setHashKeySerializer(template.getKeySerializer());
    //template.setHashValueSerializer(template.getValueSerializer());
    return template;
}

这里我们使用 GenericJackson2JsonRedisSerializer 而不是 Jackson2JsonRedisSerializer ,后者的问题是你需要为每一个需要序列化进Redis的类指定一个 Jackson2JsonRedisSerializer 因为其构造函数中需要指定一个类型来做反序列化:

redis.setValueSerializer(new Jackson2JsonRedisSerializer<Product>(Product.class));

如果我们应用中有大量对象需要缓存,这显然是不合适的,而前者直接把类型信息序列化到了JSON格式中,让一个实例可以操作多个对象的反序列化。

定制RedisCacheManager

有时候Spring Boot自动给我们配置的 RedisCacheManager 也不能满足我们应用的需求,我看到很多用法都直接声明了一个自己的RedisCacheManager,其实使用 CacheManagerCustomizer 可以对自动配置的RedisCacheManager进行定制化:

@Bean
    public CacheManagerCustomizer<RedisCacheManager> cacheManagerCustomizer() {
        return new CacheManagerCustomizer<RedisCacheManager>() {
            @Override
            public void customize(RedisCacheManager cacheManager) {
                cacheManager.setUsePrefix(true); //事实上这是Spring Boot的默认设置,为了避免key冲突

                Map<String, Long> expires = new HashMap<>();
                expires.put("myLittleCache", 12L*60*60);  // 设置过期时间 key is cache-name
                expires.put("myBiggerCache", 24L*60*60);
                cacheManager.setExpires(expires);  // expire per cache

                cacheManager.setDefaultExpiration(24*60*60);// 默认过期时间:24 hours
            }
        };
    }

II. 使用

缓存Key的生成

我们都知道Redis是一个key-value的存储系统,无论我们想要缓存什么值,都需要制定一个key。

@Cacheable(cacheNames = "user")
 public User findById(long id) {
     return userMapper.findById(id);
 }

上面的代码中, findById 方法返回的对象会被缓存起来,key由默认的 org.springframework.cache.interceptor.SimpleKeyGenerator 生成,生成策略是根据被标注方法的参数生成一个 SimpleKey 对象,然后由 RedisTemplate 中定义的KeySerializer序列化后作为key(注意 StringRedisSerializer 只能序列化String类型,对 SimpleKey 对象无能为力,你只能定义其他Serializer)。

不过大多数情况下我们都会采用自己的key生成方案,方式有两种:

  1. 实现自己的KeyGenerator;
    @Configuration
    @EnableCaching
    public class CacheConfig extends CachingConfigurerSupport {
     @Bean
     public KeyGenerator customKeyGenerator() {
         return new KeyGenerator() {
           @Override
           public Object generate(Object o, Method method, Object... objects) {
             StringBuilder sb = new StringBuilder();
             sb.append(o.getClass().getName());
             sb.append(method.getName());
             for (Object obj : objects) {
               sb.append(obj.toString());
             }
             return sb.toString();
           }
         };
    }
    }
  2. @Cacheable 标注中直接声明key:
    ```java
    @Cacheable(cacheNames = "user", key="#id.toString()") ❶
    public User findById(long id) {
    return userMapper.findById(id);
    }

@Cacheable(cacheNames = "user", key="'admin'") ❷

public User findAdmin() {

return userMapper.findAdminUser();

}

@Cacheable(cacheNames = "user", key="#userId + ':address'") ❸

public List

findUserAddress(long userId) {

return userMapper.findUserAddress(userId);

}

key的声明形式支持[SpEL](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html)。
❶ 最终生成的Redis key为:`user:100234`,user部分是因为`cacheManager.setUsePrefix(true)`,cacheName会被添加到key作为前缀避免引起key的冲突。之所以`#id.toString()`要long型转为String是因为我们设置的KeySerializer为`StringRedisSerializer`只能用来序列化String。
❷ 如果被标注方法没有参数,我们可以用一个静态的key值,最终生成的key为`user:admin`。
❸ 最终生成的key为`user:100234:address`。

这种方式更符合我们以前使用Redis的习惯,所以推荐。

### 直接使用RedisTemplate
有时候标注不能满足我们的使用场景,我们想要直接使用更底层的`RedisTemplate`。
```java
@Service
public class FeedService {

    @Resource(name="redisTemplate") ❶
    private ZSetOperations<String, Feed> feedOp;

    public List<Feed> getFeed(int count, long maxId) {
        return new ArrayList<>(feedOp.reverseRangeByScore(FEED_CACHE_KEY, 0, maxId, offset, count));
    }   
  //省略
}

❶ 我们可以直接把RedisTemplate的实例注入为 ZSetOperationsListOperationsValueOperations 等类型(Spring IoC Container帮我们做了转化工作,可以参考 org.springframework.data.redis.core.ZSetOperationsEditor )。

除了当缓存,Redis还能干啥

org.springframework.data.redis.support 包中提供了一些以Redis作为后端存储的组件,包括原子计数器和Java Collections的一些实现类。

@Service
public class ActivityService {
    RedisAtomicInteger counter;
    public ActivityService(RedisConnectionFactory connectionFactory) {
        counter = new RedisAtomicInteger(counterKey,
                connectionFactory, 1);
    }
}

以上代码创建了一个分布式的原子计数器。

III. 参考

#coding/spring


以上所述就是小编给大家介绍的《Spring Boot In Practice (1):Redis 缓存实战》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数据科学入门

数据科学入门

[美] Joel Grus / 高蓉、韩波 / 人民邮电出版社 / 2016-3 / 69.00元

数据科学是一个蓬勃发展、前途无限的行业,有人将数据科学家称为“21世纪头号性感职业”。本书从零开始讲解数据科学工作,教授数据科学工作所必需的黑客技能,并带领读者熟悉数据科学的核心知识——数学和统计学。 作者选择了功能强大、简单易学的Python语言环境,亲手搭建工具和实现算法,并精心挑选了注释良好、简洁易读的实现范例。书中涵盖的所有代码和数据都可以在GitHub上下载。 通过阅读本书,......一起来看看 《数据科学入门》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试