今天花半小时补一篇技术文章纯纯是因为早上发的那篇感悟随记很多人可能会认为不是技术文章。而一般这种文章的阅读量会远高于技术文章。为了不破坏公众号的基调,今天写篇技术文章明天一早发出去。大家上班路上看到的是:这还是一个技术公众号。但是我想说的是上篇文章我是在讲技术,如果对技术的理解过于狭隘,那在工作中会很容易进入瓶颈期。
咱们宏观到微观来审视一下:业务的服务在技术上需要解决4个问题:分布式、通信、存储和服务治理。
图片
在存储方面,spring家族在使用时做了封装就是spring data。spring data本质上是解决与存储层的通信问题,提供的是与存储层的通信规范。Redis是其中一种常用的存储。
在19年之前,Jedis还是主流的redis客户端驱动,但是近几年lettuce占据了主流的市场。这也是spring data redis的默认支持。原因是当一个Jedis连接要进行多个不同的客户端数据操作的时候有可能产生线程安全的问题,而且lettuce还支持响应式编程的模式。就是说spring data redis本身支持同步和异步两种编程模式,而lettuce支持同步、异步和响应式三种编程模式。
首先来看lettuce是什么。它是一个驱动。“驱动”通常指的是一种软件组件,它允许操作系统或应用程序与硬件或其他软件进行交互。在 Java 和其他编程语言中,驱动通常是指用于连接和操作特定类型数据库、消息队列或缓存等系统的库或框架。
驱动的四个作用
- 连接管理: 驱动负责建立与 Redis 服务器的连接,并管理连接的生命周期。
- 命令执行: 驱动提供了方法来执行 Redis 命令并处理返回的结果。
- 错误处理: 驱动处理与 Redis 交互时可能出现的错误和异常。
- 数据类型支持: 驱动通常会封装 Redis 的数据类型(如字符串、哈希、列表等),提供更易用的接口。
所以不管是Jedis还是Lettuce,都会负责连接工厂的创建。
@Bean
public LettuceConnectionFactory connectionFactory() {
RedisStandaloneConfiguration cfg = new RedisStandaloneConfiguration();
cfg.setHostName(host);
cfg.setPort(Integer.parseInt(port));
cfg.setDatabase(database);
cfg.setPassword(password);
return new LettuceConnectionFactory(cfg);
}
实际使用的时候咱们还是使用RedisTemplate
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory factory) {
// 创建实例对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
template.afterPropertiesSet();
return template;
}
有没有朋友有这样的疑惑:RedisTemplate看这个名字应该是使用了模板方法的设计模式,模板方法特征不是应该提供一个抽象类,有不同的实现吗?怎么看源码好像也没用啊。这个问题问得很好,年轻人。
为什么我知道你是个年轻人呢。因为RedisTemplate在早期的版本中的确是一个抽象方法,具体使用的时候还是需要使用它的子类,那时候是一种基于行为模式的模板方法。而现在呢?
仍然是一个模板方法的设计模式,除了可以直接使用的RedisTemplate,我们其实还有StringRedisTemplate这个子类。后来又有了一个ReactiveRedisTemplate,它其实并不是RedisTemplate的子类。
咱们提到Lettuce是支持响应式编程的。
响应式编程是一种编程范式,强调异步数据流的处理和对变化的响应。它允许程序以声明性方式处理数据流和变化,通常用于处理用户界面、事件驱动的系统、流式数据等场景。响应式编程的核心思想是将数据视为流,并对这些流中的变化作出反应。
它有几个核心概念:
- 数据流:
- 数据流是指一系列的数据变化或事件。响应式编程中,数据流可以是用户输入、网络请求、传感器数据等。
- 观察者模式:
响应式编程通常基于观察者模式,即一个对象(被观察者)维护一系列依赖于它的对象(观察者),并在其状态发生变化时自动通知这些观察者。
异步处理:
响应式编程强调非阻塞的异步处理,通过回调函数、Promises 或者流的方式来处理数据变化,而不是等待操作完成。
声明性编程:
响应式编程允许开发者以声明的方式定义数据流的处理逻辑,而不是以命令式的方式逐步执行。
响应式编程的优点
- 简化异步编程: 通过将异步操作以流的形式处理,减少了回调地狱(callback hell)的问题。
- 提高可读性: 代码更简洁,逻辑清晰,更容易理解和维护。
- 易于组合: 可以方便地将多个数据流进行组合和转换,形成复杂的逻辑。
回调地狱(Callback Hell)是指在使用异步编程时,由于多层嵌套的回调函数导致代码变得难以阅读、理解和维护的现象。它通常发生在处理多个异步操作时,每个操作都依赖于前一个操作的结果,导致代码结构像金字塔一样逐渐加深。
回调地狱的特征
- 深层嵌套: 每个异步操作的结果都需要嵌套在另一个回调中,使得代码层级过深。
- 可读性差: 多层嵌套使得代码难以理解,逻辑不清晰,增加了维护的难度。
- 错误处理复杂: 在嵌套的回调中,错误处理变得更加复杂,因为每个回调都需要单独处理错误。
Spring Data Redis默认是异步的,而使用响应式编程的公司实际也不多见。因为响应式编程是受到环境制约的。它要基于WebFlex,而WebFlex与咱们常用的Web是二选一的。