前言
Nest.js中集成了很多的后端思想,其中包括IOC和AOP思想,但是,当初次接触这两个概念时,总会模糊不清,下面,我将一一梳理一下这两个概念。
IOC
在开发后端时,我们会对业务代码进行分离。 所以会有很多对象,就比如:
- Controller 对象:接收 http 请求,调用 Service中的方法,返回响应
- Service 对象:实现业务逻辑代码
- Repository 对象:实现对数据库的增删改查
这些对象的关系是错综复杂的,Controller对象依赖于Service对象,Service对象依赖于Repository对象,这些对象都会有各自的对应关系,所以就会产生一下的代码
const repository = new Repository();
const service = new Service(repository);
const controller = new Controller(service);
在应用创建时,这些对象的依赖关系需要我们去理清楚,创建一大堆对象联系起来,还需要保证同一个对象不要多次new,这样一来,无疑是给我们的开发带来了不必要的麻烦。
这也是后端业务开发中都有的一大痛点。
解决这个痛点的方式就是 IOC(Inverse Of Control)。
Java的Spring就实现了IOC,同样在Nest.js中,也集成了IOC的思想。
因为我们需要手动去new一些对象,并去自己手动组成依赖关系,所以想到了一个办法就是当程序初始化时,扫描class的依赖声明,把这些了class都new一个实例添加到容器中。
同时,在对象创建时,把需要的依赖注入进去,这种依赖注入的方式叫做 Dependency Injection,简称 DI。
而这种方案为什么叫 IOC 也很容易理解了,本来是手动 new 依赖对象,然后组装起来,现在是声明依赖了啥,等待被注入。
从主动创建依赖到被动等待依赖注入,这就是 Inverse Of Control,反转控制。
在class上声明依赖关系,则是选择了装饰器的方式,这种方式在Java中叫做注解
比如说上述的@Injectable装饰器,就说明这个class是可注入与其他容器的。
上述的@Controller装饰器,就说明这个class是可以被注入其他容器的,例如这个容器就注入了AppService。
通过@Module装饰器声明模块,其中 controllers 是控制器,只能被注入。
providers 里可以被注入,也可以注入别的对象,比如这里的 AppService。
AOP
在开发后端时,我们会经常面对MVC架构。
MVC 是 Model View Controller 的简写。
MVC 架构下,请求会先发送给 Controller,由它调度 Model 层的 Service 来完成业务逻辑,然后返回对应的 View。
在这个过程中,Nest提供了AOP这样的(Aspect Oriented Programming)功能,也就是面向切面编程。
当一个请求过来,可能会经过 Controller(控制器)、Service(服务)、Repository(数据库访问) 的逻辑。
如果想在这些执行顺序中加入一些通用的逻辑,最容易想到的办法就是,改造Controller层,但是这样会使这些通用的逻辑影响业务逻辑,造成不便。
所以我们可以在进入Controller层之前和之后添加通用逻辑。
这样一看,是不是就类似于一个切面,将通用逻辑加入到执行顺序中,
AOP 的好处是可以把一些通用逻辑分离到切面中,保持业务逻辑的纯粹性,这样切面中的逻辑可以复用,还可以动态的增删。
Nest.js 实现 AOP 的方式一共有五种:
- Middleware(中间件)
- Guard(守卫)
- Pipe(管道)
- Interceptor(拦截器)
- ExceptionFilter(异常处理类)