框架建设实战6——缓存组件

说起分布式缓存,如今redis大行其道。不过,我们在创建缓存组件时,需要着重考虑如下几点:

1.客户端选型

本组件基于springboot2的默认实现,即lettuce客户端。不同客户端区别如下:

名称 描述 优缺点分析
jedis 1.springboot1.5.*默认 2.老牌客户端,使用稳定,但基于阻塞IO,其客户端实例本身非线程安全,要借助连接池建立物理连接 **优点:**支持全面的 Redis 操作特性(可以理解为API比较全面)。缺点:1.使用阻塞的 I/O,且其方法调用都是同步的,程序流需要等到 sockets 处理完 I/O 才能执行,不支持异步;2.Jedis 客户端实例不是线程安全的,所以需要通过连接池来使用 Jedis
Lettuce Springboot2.*默认,官方推荐 Lettuce底层基于netty,支持异步API。1个连接实例支持多线程复用。 **优点:**1.支持同步异步通信模式;2.Lettuce 的 API 是线程安全的,如果不是执行阻塞和事务操作,如BLPOP和MULTI/EXEC,多个线程就可以共享一个连接。**缺点:**学习成本相对jedis来说较高
Redisson Redisson是一个在Redis的基础上实现的 Java驻内存数据网格。基于netty框架通信机制,宗旨为促进使用者对Redis的关注分离 **优点:**1.提供一些高级用法,可提升开发效率,让开发者有更多的时间来关注业务逻辑2.提供很多分布式相关操作服务。例如分布式锁、分布式集合。可通过Redis支持延迟队列等。**缺点:**Redisson 对字符串的操作支持比较差。

2.序列化方式

同样,我们默认采用jackson的序列化方式进行缓存value的序列化和反序列化。

当然,根据大家的习惯,也许有些公司使用fastJson作为首选。或者二者兼而有之。

那如果既要满足jackson的方式,又要满足fastJson的方式应该怎么办呢?

敲重点:使用配置参数

比如我们可以使用如下配置,来控制业务接入使用何种序列化方式。

makefile 复制代码
frame.cache.serializer:jackson

指定了对应的序列化方式,可以看到配置类核心代码如下:

less 复制代码
@Bean
    @ConditionalOnMissingBean(
            name = {"redisTemplate"}
    )
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        // key的序列化直接使用StringRedisSerializer
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        //根据配置属性判断value使用何种序列化
        if(JASKSON.equalsIgnoreCase(serializerType)) {
            template.setValueSerializer(jacksonSerializer());
            template.setHashValueSerializer(jacksonSerializer());
        }
        if(FASTJSON.equalsIgnoreCase(serializerType)) {
            template.setValueSerializer(fastJsonSerializer());
            template.setHashValueSerializer(fastJsonSerializer());
        }
        template.afterPropertiesSet();
        log.info("redisClient2 configuration info:{}",template.getConnectionFactory().toString());
        return template;
    }

注意,上述的两个if,就是针对不同序列化方式做的兼容处理。

以jackson序列化为例,其配置bean如下:

typescript 复制代码
/**
     * jaskson方式
     * @return
     */
    private Jackson2JsonRedisSerializer<Object> jacksonSerializer(){
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
                new Jackson2JsonRedisSerializer<>(Object.class);

        // ObjectMapper 将Json反序列化成Java对象
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.activateDefaultTyping(
                LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL,
                JsonTypeInfo.As.WRAPPER_ARRAY);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        return jackson2JsonRedisSerializer;
    }

3.兼容性

抛个问题:如果有些业务不需要接入cache,有些需要接入,那我们有哪些方式可以处理呢?

a.pom方式

控制是否加入pom依赖,或者排除依赖

b.Conditional语义

读者可以使用springboot关于Conditional的语法控制相关service bean的创建

比如:@ConditionalOnMissingBean、@ConditionalOnBean、@@ConditionalOn****

c.注解开关

比如使用EnableCache注解(其他组件类似,通过Enable的语义控制业务是否激活某个功能组)

4.防腐层设计

我们需要考虑接入redis服务器的方式,就要对公司目前的redis部署架构进行调研。比如主从模式、集群模式,还是哨兵模式?

一般而言,公司的运维服务器架构不会轻易变化的。特别是如果中间件是基于云端的服务,那么架构模式一般是固定下来的。

如果采用的是主备模式,那么我们可以直接基于springboot的redis的starter就可以进行服务端连接。

xml 复制代码
<dependency> 
      <groupId>com.fasterxml.jackson.core</groupId>  
      <artifactId>jackson-annotations</artifactId> 
    </dependency>  
    <dependency> 
      <groupId>com.fasterxml.jackson.core</groupId>  
      <artifactId>jackson-databind</artifactId> 
    </dependency>  
    <dependency> 
      <groupId>org.springframework.boot</groupId>  
      <artifactId>spring-boot-starter-data-redis</artifactId> 
    </dependency> 

并配置客户端连接入参即可:

ini 复制代码
spring.redis.host=****
spring.redis.port=***
spring.redis.password=***

但,如果采取的是其他模式,就需要我们自行创建客户端的连接bean了。


思考题:

如果我们选用了redis作为分布式锁的实现,那么此功能是要跟缓存组件放在一起呢?还是独立出来一个分布式锁组件更合适?虽然两者都是基于redis的实现。

相关推荐
阳光是sunny41 分钟前
LangGraph中的Reducer是什么
前端·人工智能·后端
灯澜忆梦1 小时前
GO_并发编程---定时器
开发语言·后端·golang
阳光是sunny1 小时前
从链到图:LangGraph 入门基础全解析
前端·人工智能·后端
皮皮林5511 小时前
开源实力派,给本地 AI 装上深度调研能力,一张 3090 跑到 95.7 分!
后端
努力的小雨2 小时前
把 Windows 桌面图标做成一个会自己运转的小世界
后端
武子康3 小时前
Search Console Platform Properties 扩大 SEO 资产边界:从 Page Ranking 到 Topic Coverage(5 类误读边界 + 3 表数据层设计)
前端·人工智能·后端
腾渊信息科技公司3 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
IT_陈寒4 小时前
Vue这个特性差点让我加班到凌晨,谁懂啊
前端·人工智能·后端
段一凡-华北理工大学5 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
码事漫谈5 小时前
1999年的电商前夜和2026年的AI前夜 历史押韵但从不重复
后端