ARTS 源于极客时间《左耳听风》专栏组织的一个学习打卡活动,四个字母对应着四个行动准则:
- Algorithm:每周至少做一个 leetcode 的算法题
- Review:阅读并点评至少一篇英文技术文章
- Tip:学习至少一个技术技巧
- Share:分享一篇有观点和思考的技术文章
Review
阅读并点评至少一篇英文技术文章
Pattern: API Gateway / Backends for Frontends
API Gateway 的背景
该文章介绍了微服务架构设计中的一个重要模式 —— API 网关模式,文章先从一个例子出发,如何设计亚马逊的的产品详情页,一个详情页需要调用多个后端服务,面临的问题包括:
- 客户端需要对多个服务发起多个请求,整体的传输效率较低,特别是手机端
- 后端实例的地址可能会动态变化
- 服务的划分也有可能是变化的,需要对客户端隐藏
- 多终端场景下,不同的终端需要不同类型的数据格式
- 有些后端服务使用的协议可能对 Web 是不友好的
解决方案
通过实现一个 API 网关来作为所有客户端请求的入口,网关收到请求后可以简单地代理/路由到某个服务,或者请求多个服务然后聚合他们的返回结果,这些处理对客户端都是透明的。
可以为不同的客户端提供不同的适配逻辑,还可以承担安全控制的职责。
P.S: 笔者曾经就遇到过,公司大规模采用的 Web 框架在 API 鉴权逻辑上被发现存在安全漏洞,需要逐个服务修复,修复成本很高,如果之前采用 API 网关模式,把鉴权逻辑交给网关来做的话,我们就只需要修复网关这一个地方了,整体的服务质量更为可控,这也是“权力集中”的好处之一。
还有一种变种形式,一种客户端对应一个 API 网关。
好处
- 微服务的划分和各个实例的地址对客户端完全透明
- 为不同类型的客户端提供最佳的 API
- 减少客户端的网络请求数,提升传输效率,简化客户端的请求逻辑
- 后端内部的服务可以自由选择协议,网关会对其进行转化,最终暴露为 Web 友好的 API
Tip
学习至少一个技术技巧
-
开始在个人项目里实践 Gradle:
- 相比较 Maven,配置文件可读性更强,语法更优雅,可定制性也更强
- 增量构建的概念也更先进,提高构建效率
-
进一步熟悉 jOOQ:
- SQL 函数的使用,e.g:
DSL.sum() - 构建 DSL 的关键,了解
Condition类
- SQL 函数的使用,e.g:
-
Java Time API 最佳实践:
Java 8 Time API 的优越性就不用赘述了,不过很多框架对 java 8 Time API 的原生支持不是很好,比如MyBatis和Jackson需要引入额外的插件才能支持LocalDateTime字段的(反)序列化。
直接在 Web 层的 VO 和 持久层的 PO 声明LocalDateTime也许不是最好的选择,可以在 VO 和 PO 里使用旧的时间类型,当有操作时间/日期的需求时,再在 Service 层里将其转成LocalDateTime, 享受其 API 的灵活性。
发现java.sql.Timestamp和LocalDateTime互转十分方便:
timestamp.toLocalDateTime()&Timestamp.valueOf(localDateTime)
建议把 VO 和 PO 里字段的时间类型都设置成java.sql.Timestamp,虽然 Web 层的 VO 使用java.sql包下的类会显得有些奇怪。 -
vim tips:
- 安装 nedtree 等插件,尝试用 vim 写代码
- vim split & tabs
Share
分享一篇有观点和思考的技术文章
Algorithm
中规中矩,比较简单的题目
class Solution {
public String intToRoman(int num) {
StringBuilder sb = new StringBuilder();
List<BaseNum> baseNums = initBaseNums();
for (BaseNum b : baseNums) {
while (num >= b.value) {
num -= b.value;
sb.append(b.roman);
}
}
return sb.toString();
}
private List<BaseNum> initBaseNums() {
List<BaseNum> baseNums = new ArrayList<>();
baseNums.add(new BaseNum(1000, "M"));
baseNums.add(new BaseNum(900, "CM"));
baseNums.add(new BaseNum(500, "D"));
baseNums.add(new BaseNum(400, "CD"));
baseNums.add(new BaseNum(100, "C"));
baseNums.add(new BaseNum(90, "XC"));
baseNums.add(new BaseNum(50, "L"));
baseNums.add(new BaseNum(40, "XL"));
baseNums.add(new BaseNum(10, "X"));
baseNums.add(new BaseNum(9, "IX"));
baseNums.add(new BaseNum(5, "V"));
baseNums.add(new BaseNum(4, "IV"));
baseNums.add(new BaseNum(1, "I"));
return baseNums;
}
private static class BaseNum {
int value;
String roman;
public BaseNum(int value, String roman) {
this.value = value;
this.roman = roman;
}
}
}