0%

面向切面编程(AOP)

首先 AOP 是一种编程方式

为了理解AOP的概念,我们先用OOP举例,比如一个业务组件BookService,它有几个业务方法:

  • createBook:添加新的Book;
  • updateBook:修改Book;
  • deleteBook:删除Book;

对每个业务方法,例如,createBook(),除了业务逻辑,还需要安全检查、日志记录和事务处理,它的代码像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BookService {
public void createBook(Book book) {
securityCheck();
Transaction tx = startTransaction();
try {
// 核心业务逻辑
tx.commit();
} catch (RuntimeException e) {
tx.rollback();
throw e;
}
log("created book: " + book);
}
}

继续编写updateBook(),代码如下:

阅读全文 »

对 DI(依赖注入) 和 IOC(控制反转) 的理解

简单来说,类A依赖类B,但A不控制B的创建和销毁,仅使用B,那么B的控制权则交给A之外处理,这叫控制反转(IOC)

由于A依赖于B,因此在A中必然要使用B的实例,我们可以通过A的构造函数将B的实例注入。

1
2
3
4
5
6
7
8
9
class B { }
class A {
constructor(b: B) {
console.log(b);
}
}
const b = new B();
// 将B的实例注入到a中
const a = new A(b);

和原来的主要区别在于: 之前是在 class A 之中实例化 B,现在是直接把实例作为参数传入。

接下来我将通过代码的形式对比使用依赖注入相比非依赖注入的好处体现在哪。

非依赖注入代码

阅读全文 »

mongoose exec 方法

因为我使用 mongoose 的 Query 方法一直都没有加 exec() 方法,但是使用 nestjs 生成的 service 文件里的查询方法,尾巴会带上一个 exec()方法,所以我查了一下文档,了解这个 exec()方法加与不加有什么区别.

正常的 Query 方法

阅读全文 »

背景

前端和测试反馈说登录功能出现 bug,通过 F12 定位到是 getUserInfo 接口返回 400
重点是这个接口的报错和登录的账号有关,有些账号报 400,有些账号报 403,还有些账号登录成功.

阅读全文 »

普通占位符

1
2
3
4
5
6
占位符     说明                           举例                   输出
%v 相应值的默认格式。 Printf("%v", people) {zhangsan},
%+v 打印结构体时,会添加字段名 Printf("%+v", people) {Name:zhangsan}
%#v 相应值的Go语法表示 Printf("#v", people) main.Human{Name:"zhangsan"}
%T 相应值的类型的Go语法表示 Printf("%T", people) main.Human
%% 字面上的百分号,并非值的占位符 Printf("%%") %

布尔占位符

1
2
占位符       说明                举例                     输出
%t true 或 false。 Printf("%t", true) true
阅读全文 »

golang 学习笔记

语法部分

数组 [n]T

语法: 变量名 := [数组长度]数据类型{数组内数据}
例如: country := [3]string{‘中国’,’日本’,’韩国’}
也可以只生命,不赋值,或者不填满数组
var country [5]string
需要注意的是这个时候不能使用 :=
语法允许 var country [5]string
或者 country := [5]string{}
golang 的数组是固定长度的,如果想使用不固定长度的,可以使用切片(slice)

阅读全文 »

libuv 是什么

libuv是一个高性能的,事件驱动的I/O库,并且提供了跨平台(如windows, linux)的API。对 node.js 来说 libuv 提供了 event-loop,以及基于 I/O和其他时间通知的回调函数.简单的说 node.js 之所以是天生的异步,就是因为 node.js 使用了 libuv 实现.

什么是微服务

微服务没有一个明确的定义,只能通过和传统的服务对比,才比较好理解什么是微服务.
传统服务是将绝大多数的业务 api 都集成在一个工程里.

优点是:

  1. 开发简单直接,集中式管理
  2. 基本不会重复开发
  3. 功能都在本地,没有分布式的管理开销和调用开销

但是同样的,缺点也很多:

  1. 开发效率低:所有的开发在一个项目改代码,递交代码相互等待,代码冲突不断
  2. 代码维护难:代码功能耦合在一起,新人不知道何从下手
  3. 部署不灵活:构建时间长,任何小修改必须重新构建整个项目,这个过程往往很长
  4. 稳定性不高:一个微不足道的小问题,可以导致整个应用挂掉
  5. 扩展性不够:无法满足高并发情况下的业务需求

所以对比之下就有了微服务架构.其思路大致上来说,就是将原来庞大的工程拆分成n 个小的,互相连接的工程.
比如原来是整个电商系统的后端服务,现在拆分成:

  • 用户服务
  • 商品服务
  • 订单服务
  • 物流服务
  • 等等…
阅读全文 »

TypeScript笔记

基础类型

unknown类型

unknown 类型用于解决any类型使用过于宽松的问题, unknown可以赋任何值,但是unknown不能赋值给其他参数(any和unknown除外)
any类型甚至可以是function,但是unknown类型在赋值之前无法当做方法或者数组来使用

tuple元祖

TS的数据要求是同种类型的值组成,当需要不同类型的值组成组数时,就需要用到tuple
元祖需要在申明变量时就固定值类型与数量比如:

1
2
// 不能不符合类型,也不能多不能少
const tupleValue: [string, boolean, number] = ['abc', false, 123];

object,Object,{}的区别

object是一个数据类型,可用于声明变量,但是微软现在不建议这样使用,而是建议使用Record<string, unknown>

Object 是所有 Object 类的实例类型,与JS的Object使用类似

{} 是一个没有成员的对象,是一个具体的对象数据,不是一个类型

Never 类型

never 表示那些用不存在的值的类型,常用于断言或者保证方法逻辑性
使用 never 避免出现新增了联合类型没有对应的实现,目的就是写出类型绝对安全的代码

阅读全文 »

背景

总所周知服务器的承受能力是有限度的,当请求量超过承受量时,可能会导致服务器宕机,连原本能解决的请求都无法处理.就比如地铁,本来每分钟能运输一万人,但是突然有十万人一起涌进地铁站,导致站台过于拥挤,人们都无法顺利上车,结果就是连原本排在最前面的一万人都无法上地铁,这个时候就可以采取限流策略,限制进站人数,让地铁能顺利的将一批批的乘客送走.

分层限流

  1. 限流总并发/连接/请求数
  2. 限制总资源数
  3. 限流某个接口的总并发/请求数
  4. 限流某个接口的时间窗请求数
  5. 平滑限流某个接口的请求数:前面几个限流都不能很好的应对突发请求,即瞬间请求可能都被允许,从而导致一些问题(极限值请求),因此在一些场景中需要对突发请求进行整形,整形为平均速率请求处理(比如5r/s,则每隔200ms处理一个请求,平滑了速率)。

限流策略

限流策略主要有两大类共四种

  • 计数器限流
    • 固定窗口
    • 滑动窗口
  • 桶限流
    • 令牌桶
    • 漏桶
阅读全文 »