import { isResolveMode } from '../utils'; import { ContainerProvider } from '../container'; import { AfterReturningAdvice, AfterThrowsAdvice, AopProxy, AopProxyFactory, AOP_TAG, MethodBeforeAdvice, ProxyConfig } from './aop-protocol'; import { Component } from '../annotation'; import { interfaces } from 'inversify'; @Component({ id: AopProxyFactory, proxy: false }) export class AopProxyFactoryImpl implements AopProxyFactory { protected getAdvices(id: interfaces.ServiceIdentifier, tagValues: string[]) { const container = ContainerProvider.provide(); const advices: T[] = []; for (const tagValue of tagValues) { if (container.isBoundTagged(id, AOP_TAG, tagValue)) { advices.push(...container.getAllTagged(id, AOP_TAG, tagValue)); } } return advices; } create(config: ProxyConfig): AopProxy { const { metadata: { sysTags } } = config; const proxy = new Proxy(config.target, { get: (target, method, receiver) => { if (isResolveMode()) { return target; } const func = target[method]; if (typeof func === 'function') { return async (...args: any[]) => { try { const beforeAdvices = this.getAdvices(MethodBeforeAdvice, sysTags!); for (const advice of beforeAdvices) { await advice.before(method, args, target); } const returnValue = await func.apply(target, args); const afterReturningAdvices = this.getAdvices(AfterReturningAdvice, sysTags!); for (const advice of afterReturningAdvices) { await advice.afterReturning(returnValue, method, args, target); } return returnValue; } catch (error) { const afterThrowsAdvices = this.getAdvices(AfterThrowsAdvice, sysTags!); for (const advice of afterThrowsAdvices) { await advice.afterThrows(error, method, args, target); } throw error; } }; } return func; } }); return { getProxy() { return proxy; } }; } }