AOP編程有三大場景:控制器切面,內(nèi)部切面,外部切面,你get到了嗎?
如果用過NestJS框架都知道,在NestJS框架中AOP編程包括以下幾個能力:Middleware、Guard、Interceptor、Pipe、Filter。事實上AOP編程的應(yīng)用場景更廣泛,上述所列5個能力僅僅是AOP編程的子集。下面,我們看看在VonaJS框架中,AOP編程是怎樣的。
VonaJS AOP編程
VonaJS AOP 編程包括三個方面的能力:
控制器切面: 為 Controller 方法切入邏輯內(nèi)部切面: 在 Class 內(nèi)部,為任何 Class 的任何方法切入邏輯外部切面: 在不改變 Class 源碼的前提下,從外部為任何 Class 的任何方法切入邏輯
控制器切面
控制器切面清單
- Middleware
- Guard
- Intercepter
- Pipe
- Filter
執(zhí)行時序圖
控制器切面的執(zhí)行時序圖如下:

洋蔥模型:Middleware和Intercepter支持洋蔥模型,允許在Controller Action之前和之后執(zhí)行切面邏輯Middleware: 針對不同的執(zhí)行時序節(jié)點,系統(tǒng)提供了三種 Middleware:Middleware System、Middleware Global和Middleware Local,從而可以實現(xiàn)更精細化的切面邏輯Route Match: 只有Middleware System在路由匹配之前執(zhí)行,其余在路由匹配之后執(zhí)行Filter: 任何環(huán)節(jié)拋出異常,都會執(zhí)行Filter,從而自定義錯誤信息和錯誤日志的處理邏輯
內(nèi)部切面
內(nèi)部切面提供兩個機制:AOP Method和魔術(shù)方法
1. AOP Method
直接在 Class Method 上通過裝飾器切入邏輯
舉例:數(shù)據(jù)庫事務(wù)
class ServiceStudent {
+ @Database.transaction()
async update(id: TableIdentity, student: DtoStudentUpdate) {
return await this.scope.model.student.updateById(id, student);
}
}
@Database.transaction:通過AOP Method機制實現(xiàn)的裝飾器,可以直接提供數(shù)據(jù)庫事務(wù)能力
舉例:日志
class ServiceStudent {
+ @Log()
async update(id: TableIdentity, student: DtoStudentUpdate) {
return await this.scope.model.student.updateById(id, student);
}
}
@Log:通過AOP Method機制實現(xiàn)的裝飾器,可以直接提供日志能力
2. 魔術(shù)方法
可以在 Class 內(nèi)部通過__get__和__set__切入動態(tài)屬性或方法
舉例:獲取 model 實例
class ServiceStudent {
async update(id: TableIdentity, student: DtoStudentUpdate) {
+ return await this.scope.model.student.updateById(id, student);
}
}
this.scope.model.xxx: 沒有使用依賴注入,而是使用依賴查找,直接通過 scope 對象獲取 model 實例,從而簡化代碼的書寫風(fēng)格
實現(xiàn)思路
系統(tǒng)提供了一個 Class ServiceModelResolver,用于實現(xiàn) model 實例的動態(tài)解析,代碼如下:
class ServiceModelResolver {
protected __get__(prop: string) {
const beanFullName = `${this[SymbolModuleScope]}.model.${prop}`;
return this.bean._getBean(beanFullName as any);
}
}
- 當調(diào)用
this.scope.model.student時,會自動執(zhí)行__get__方法,并且傳入?yún)?shù)prop: 'student' - 將參數(shù)
prop與當前模塊名稱合并成beanFullName - 通過
beanFullName從全局容器中獲取 model 實例,并返回給調(diào)用者
外部切面
仍以 Class ServiceStudent的update方法為例,通過外部切面來實現(xiàn)日志能力:
import { Aop } from 'vona-module-a-aspect';
@Aop({ match: 'demo-student.service.student' })
class AopLog {
async update(_args: Parameters<any>, next: Function, _receiver: any) {
const timeBegin = Date.now();
const res = await next();
const timeEnd = Date.now();
console.log('time: ', timeEnd - timeBegin);
return res;
}
}
@Aop: 此裝飾器用于實現(xiàn)外部切面match: 用于將 ClassAopLog與 ClassServiceStudent關(guān)聯(lián),ServiceStudent的 beanFullName 是demo-student.service.studentupdate: 在AopLog中提供與ServiceStudent同名的方法update,實現(xiàn)自定義邏輯即可

如果用過NestJS框架都知道,在NestJS框架中AOP編程包括以下幾個能力:Middleware、Guard、Interceptor、Pipe、Filter。事實上AOP編程的應(yīng)用場景更廣泛,上述所列5個能力僅僅是AOP編程的子集。下面,我們看看在VonaJS框架中,AOP編程是怎樣的。
浙公網(wǎng)安備 33010602011771號