Spring Boot Redis 使用

背景

在项目中集成缓存,有多种方法,在Spring Boot中,我们一般采用自带的缓存框架,使用方法如下

Redis的使用

添加配置

配置添加如下,spring节点下面添加redis配置

spring:
  redis:
    host: test.redis.rds.aliyuncs.com
    port: 6379
    password: xxxxxx
    database: 0

项目集成

添加引用

pox.xml文件添加如下配置

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
缓存配置

自动注入缓存配置并启用,添加Configuration和EnableCaching注解
配置缓存管理器和模板

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {

    public static final String redisKeyPrefix = "erp:oms:";

    /**
     * CacheManager 配置,如果有多个需要,可以加多个,默认的增加【@Primary】注解,其它的【@Bean(name = "XXX")】
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>();

        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .prefixCacheNameWith(redisKeyPrefix) // redis的key的前缀
                .entryTtl(Duration.ofMinutes(30)) // 过期时间30分钟
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
                .disableCachingNullValues();

        return RedisCacheManager.builder(factory)
                .initialCacheNames(configurationMap.keySet())
                .withInitialCacheConfigurations(configurationMap)
                .cacheDefaults(config)
                .build();
    }

    /**
     * RedisTemplate 配置
     */
    @Bean
    public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        template.setKeySerializer(keySerializer());
        template.setValueSerializer(valueSerializer());

        template.setHashKeySerializer(keySerializer());
        template.setHashValueSerializer(valueSerializer());

        template.afterPropertiesSet();
        return template;
    }

    /**
     * key序列化
     */
    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    /**
     * value序列化
     */
    private RedisSerializer<Object> valueSerializer() {
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        // 此项必须配置,否则如果序列化的对象里边还有对象,会报如下错误:
        // java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
        objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

        // 如果java.time包下Json报错,添加如下两行代码
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new JavaTimeModule());

        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

        return jackson2JsonRedisSerializer;
    }
}
缓存使用
@Service
@CacheConfig(cacheNames = "branch")
public class BranchServiceImpl extends ServiceImpl<BranchDao, BranchPO> implements BranchService {
    @Resource
    private BranchConverter branchConverter;

    /**
     * 根据id获取分公司信息
     */
    @Override
    @Cacheable(value = "getByBranchId", key = "#branchId", unless = "#result == null")
    public BranchDTO getByBranchId(int branchId) {
        return branchConverter.toDTO(this.getById(branchId));
    }
}

CacheConfig(cacheNames = "branch"):配置到类上面,类的默认配置;cacheNames:默认缓存名称
Cacheable(value = "getByBranchId", key = "#branchId", unless = "#result == null"):配置到类上面,value :缓存名称,如果为空,默认采用cacheNames;key:指定哪个参数的值,作为key

高级用法

假如我们需要定义多个Redis管理器,该怎么处理?
又或者我们想自定义缓存实现,需要怎么做?

多管理器的使用

定义多个Redis管理器
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    @Primary
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        
    }

    @Bean(name = "cacheManagerSpecial")
    public CacheManager cacheManagerSpecial(RedisConnectionFactory factory) {
        
    }
}

注意:上述代码已经删除内容,只保留了关键结构
解释说明

  1. 我们只需要再定义一个CacheManager (指定名称=cacheManagerSpecial)即可
  2. 原有的cacheManager需要增加@Primary注解,避免找不到主缓存管理器而报错
  3. 使用的地方:@CacheConfig(cacheNames = "branch", cacheManager = "cacheManagerSpecial"),多增加一个cacheManager 指定即可
使用管理器
@Service
@CacheConfig(cacheNames = "branch", cacheManager = "cacheManagerSpecial")
public class BranchServiceImpl

在CacheConfig里面,指定cacheManager 即可,完整代码参考项目集成

RedisTemplate模板使用

如果我们想自定义缓存实现,可以采用RedisTemplate来实现,同样在缓存配置里面增加redisTemplate配置,如下

定义模板
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    /**
     * RedisTemplate 配置
     */
    @Bean
    public RedisTemplate<?, ?> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        template.setKeySerializer(RedisSerializer.string());
        template.setValueSerializer(RedisSerializer.json());

        template.setHashKeySerializer(RedisSerializer.string());
        template.setHashValueSerializer(RedisSerializer.json());

        template.afterPropertiesSet();
        return template;
    }
}
自定义缓存实现
@Service
@CacheConfig(cacheNames = "cacheService")
public class CacheServiceImpl {
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Object getCache(String key){
        Object result = null;
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        result = operations.get(key);
        return result;
    }

    @Override
    public void setCache(String key, String value) {
        ValueOperations<String, Object> operations = this.redisTemplate.opsForValue();
        operations.set(key, value);
        this.redisTemplate.expire(key, Duration.ofMinutes(1));
    }
}

使用说明

  1. 增加RedisTemplate注入,使用定义的模板进行操作
  2. 使用模板提供的Operations接口,对缓存进行操作
RedisTemplate五种数据结构的操作
redisTemplate.opsForValue(); //操作字符串
redisTemplate.opsForHash(); //操作hash
redisTemplate.opsForList(); //操作list
redisTemplate.opsForSet(); //操作set
redisTemplate.opsForZSet(); //操作有序zset

Key和Value序列化和反序列化

  1. JdkSerializationRedisSerializer:POJO对象的存取场景,使用JDK本身序列化机制,将pojo类通过ObjectInputStream/ObjectOutputStream进行序列化操作,最终redis-server中将存储字节序列。是目前最常用的序列化策略。
  2. StringRedisSerializer:Key或者value为字符串的场景,根据指定的charset对数据的字节序列编码成string,是“new String(bytes, charset)”和“string.getBytes(charset)”的直接封装。是最轻量级和高效的策略。
  3. JacksonJsonRedisSerializer:jackson-json工具提供了javabean与json之间的转换能力,可以将pojo实例序列化成json格式存储在redis中,也可以将json格式的数据转换成pojo实例。因为jackson工具在序列化和反序列化时,需要明确指定Class类型,因此此策略封装起来稍微复杂。【需要jackson-mapper-asl工具支持】
  4. OxmSerializer:提供了将javabean与xml之间的转换能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存储的数据将是xml工具。不过使用此策略,编程将会有些难度,而且效率最低;不建议使用。【需要spring-oxm模块的支持】

注解解析

CacheConfig

//指定缓存组件的名字
@AliasFor("cacheNames")
String[] value() default {};

//指定缓存组件的名字
@AliasFor("value")
String[] cacheNames() default {};

// 缓存数据使用的Key,
String key() default "";

// key的生成器,可以自己指定key的生成组件id; 
// key 与 keyGenerator 两个只能选一个,不能同时指定
String keyGenerator() default "";

// 指定缓存管理器,
String cacheManager() default "";

//指定获得解析器,cacheManager、cacheResolver 两者取其一
String cacheResolver() default "";

// 符合condition条件,才缓存
String condition() default "";

// 和 codition 条件相反才成立
String unless() default "";

// 是否使用异步模式
boolean sync() default false;

// 只有@CacheEvict 有这个属性
// 清空所有缓存信息
boolean allEntries() default false;

// 只有@CacheEvict 有这个属性
// 缓存的清除是否在方法之前执行
// beforeInvocation=false  默认是在方法之后执行
boolean beforeInvocation() default false;

其它常用注解

@Cacheable缓存方法注解,先查询缓存中是否存在,存在则返回缓存内容,否则执行方法后,并把返回结果缓存起来
@CacheEvict删除指定缓存
@CachePut更新并刷新缓存,先执行方法内容,然后更新缓存
@EnableCaching这个是一个复合注解,可以拥有同时配置上面3个注解的功能

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容