序言
Redis 服务器是一个事件驱动程序,服务器需要处理以下两类事件:
- 文件事件:Redis 服务器通过套接字(
Socket)与客户端 (或其他 Redis 服务器)进行连接,文件事件就是服务器对套接字操作的抽象。服务器与客户端的通信会产生相应的文件事件,而服务器则通过监听并处理这些事件来完成一系列网络通信操作。 - 时间事件:Redis 服务器中的一些操作需要在给定的时间点执行,而时间事件就是服务器低这类定时操作的抽象。
官方文档:Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.
翻译:Redis 是 一个开源(BSD 许可),内存数据结构存储,用作数据库,缓存和消息代理。它支持数据结构,如字符串,散列,列表,集合,带有范围查询的排序集,位图,超级日志,具有半径查询和流的地理空间索引。
Redis 具有内置复制,Lua 脚本,LRU 回收,事务和不同级别的磁盘持久性,同时通过 Redis Sentinel 提供高可用性,通过 Redis Cluster 提供自动分区。
对互联网中的数据而言,一般都会存储在关系型数据库中,将数据解耦排列的整整齐齐,看着会很舒服,但若碰上了海量的并发数据,程序又没处理好,用户用起来可能就不太舒服了,用户不舒服老板就不舒服,这个时候就要拿程序员祭天了——产品没优化好今天不准下班!
关系型数据库为什么不太适合处理海量的并发数据呢?这是因为它存在了一些限制:
那么,我们可能预期希望有一个东西能解决这些问题:
这个东西就是 NoSQL 了。
HTTP 是无状态协议,它不对之前发生过的请求和响应的状态进行管理。也就是说,无法根据之前的状态进行本次的请求管理,服务器不知道用户上一次做了什么,这严重阻碍了交互式 Web 应用程序的实现。
在典型的网上购物场景中,用户浏览了几个页面买了件衣服。最后结帐时,由于 HTTP 的无状态性,不通过额外的手段,服务器并不知道用户到底买了什么,
不可否认,无状态协议有它的优点,由于不必保存状态,自然可以减少服务器的压力。
但是,用户该如何在网站上购物呢?总不可能辛辛苦苦挑了件衣服给前台小姐姐(第一次请求),出去接个电话的功夫回来后准备结账(第二次请求),可前台小姐姐却说:小哥哥你谁啊?
为此,引入了会话跟踪技术。
Servlet(Server Applet),全称 Java Servlet,未有中文译文。是用 Java 编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的 Servlet 是指 Java 语言实现的一个接口,广义的 Servlet 是指任何实现了这个 Servlet 接口的类),一般情况下,人们将 Servlet 理解为后者
简单来讲,Servlet就是运行在服务端的小程序,用来将客户端发送过来的 HTTP 请求解析封装进相关的Servlet对象中,当开发者对该对象的数据进行处理后又封装到另一个Servlet对象中,转换成 HTTP 响应返回给客户端。
为了适应新时代,国家大力推广,支持各大中小企业打造“无纸化系统”。
企业使用“无纸化办公”系统,将许多传统工作从线下转为线上,以电子文件替代有纸化文件,不仅能降低企业成本,而且对使用者友好,对自然环境友好,一举多得!
在以前,人们若想办理证件,大致需要经历以下流程:
在此流程下办证,人们不仅要在各个地方来回跑,十分花费时间,而且,若文件有一个地方填错了,还得重新走一遍流程。。。
而现在,将办理证件的流程信息化,在对应电子化系统中进行操作,那么,一切都变得简单了:
通过“无纸化办公”系统,人们只需要在网上动动小手,当流程办理完成后,直接去证件办理中心领取,只需要跑一次,大大节约了时间(另外如果系统支持快递送件,那都不用跑了)。
对于上面谈论的电子化办证流程,其实是需要程序员根据标准化的文档流程进行抽象设计,最终进行代码实现的,针对这个过程,下面我们分析一下。
首先,程序员需要开发一个审批流系统,按需求规则去定义一个审批流模版,针对办证的各个步骤,转换为审批流当中的一个个节点。
另外,审批流系统需要对接其他第三方的系统,因为具体办证的业务是政务机构提供的,而审批流系统并不负责此业务。
分析下来,那么代码实现上,主要时间花费在两块:
本文不谈论第一点,因为市面上现有的审批流系统非常多,具体根据需要去调研实现即可,那么,第二点如何改如何考量呢?
由于办证相关业务是由政务机构提供,对审批流系统开发人而言,必须按其他机构提供的接口文档进行对接工作,因为需要连调测试工作,是比较耗费时间的。
当然,我们在进行接口文档对接前,首先应该是梳理下大致的流程步骤,那么,我们画一个流程图出来吧:

从流程图可知,对接第三方系统,大致需要以下接口:
在审批流系统已完成,但是还未对接第三方系统的情况下,我们先思考一下:关于对接第三方系统的代码,应该写在哪里?
直接嵌入到各个流程节点当中嘛?
当然不是,我们应当是定义出一个单独的接口服务,提供给审批流调用。
那么,我们应该会定义一个这样的接口,然后使用相应的实现类去实现它:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31public interface IThirdCardService {
/**
* 申请接口
*
* @param applyParams
*/
void apply(Object applyParams);
/**
* 文件上传接口
*
* @param uploadParams
*/
void upload(Object uploadParams);
/**
* 状态查询接口
*
* @param queryStatusParams
*/
void queryStatus(Object queryStatusParams);
/**
* 二次申请接口
*
* @param reApplyParams
*/
void reApply(Object reApplyParams);
}
我们这么做会有什么问题吗?
现在来看,确实是没啥问题的,我们现在对接了 A 办证系统,而 A 办证系统支持办理 A1、A2、A3 等种类的证件。
但是,客户之后反馈要办只有 B 办证系统支持的 B1、B2、B3 类证件,而 A 办证系统并不支持。
产品经理说:这肯定不行呀,客户的需求我们得满足呀,开发老弟,麻烦再去接入 B 办证系统吧!
开发同学:……
世界上没有两片完全相同的树叶,对 A、B 办证系统同样如此,虽然两个系统大体办证流程差不多,但部分地方还是会存在差异,比如说:
开发同学分析了下需求,既然这样,我再写一个原接口的实现类,然后实现一下,这不就是策略模式吗,简单呀!
哎,这代码怎么看起来不对劲啊?哦,少了个校验接口,emmm,怎么办呢?
我再去接口里面加个文件校验方法吧。
嗯?怎么又报错了?哦哦,A 办证系统的实现类没有实现该方法,我再去 A 办证系统的实现类实现下。
这代码看起来怎么怪怪的,而且,我发现有些代码重复了。
从前面知道了,现在的代码是有一定问题的:
显而易见,策略模式无法应对这种情况,策略模式关注的是相同行为的抽象,这种情况根本就不应该使用策略模式。
不过没关系,我们可以使用另一种设计模式——模版方法模式。
现在,即使再新增一个 C 办证系统(提供 C1、C2 证件办理),我们也只需要去新增一个模版的实现类去继承模版类即可。
通过继承,子类可以共用相同的代码,也可以各自实现不同的代码,还可以根据需要,去实现钩子函数(某些相同或不同的代码)。
模板方法模式是一种行为设计模式, 它在超类中定义了一个算法的框架,使得子类 可以在不改变一个算法的结构的情况下,重定义该算法的某些特定步骤。
| 时间 | 说明 |
|---|---|
| 2019-03-29 | 初版 |
| 2022-07-19 | 完全重构 |
假如现在你需要做一个针对第三方接口的监控预警功能(配置的指标超出阈值进行短信邮件预警),需要计算应用集成的第三方接口的各种指标,比如:
由于这些指标分别存储在 MySQL、Redis、ElasticSearch,因此计算的逻辑并不相同,所以你可能会写出下面的代码:
1 | // 指标枚举 |
1 | public getCalculateValue(...){ |
由于各个指标的计算方式并不相同,所以需要分别写代码进行计算,抽离出了各种方法。
从代码设计可以发现:
为了降低代码复杂性,使设计解耦,让程序看起来简洁且能应对未来的变化,可以使用策略模式来优化原有代码,最终改造后代码可以变成这样:1
2
3
4
5
6
7// 优化后的代码
public getCalculateValue(...){
Integer indexType = index.getType();
IndexStatisticsStrategy routedStrategy = indexStatisticsStrategyContext.getRoutedStrategy(indexType);
Double calculateValue = routedStrategy.calculate(indexType);
return calculateValue;
}
改造后的代码看起来是不是非常简洁?
那么,策略模式是什么,又如何使用呢?
下面跟随本文来了解下吧!
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在Spring Framework中。正式名称“Spring Web MVC”,来自其源模块(spring-webmvc)的名称,但它通常被称为“Spring MVC”。