import {AdviceType, ComponentType} from "../enum" import JoinPoint from "../type/impl/aop/advice/JoinPoint" import {IAdvice, IAspect, IComponent, IPointcut} from "../type/interface" import {PojoType} from "../type/type" import ContextContainer from "./ContextContainer" import DecorateRegistCenter from "./DecorateRegistCenter" import {getInstanceMethods} from '../util' import { MysqlError } from "mysql" export default class AspectBuilder{ private tmplDaoPool: Map = new Map() constructor(){ this.init() } private init(): void{ const { aspects = >[], pointcuts = >[], advices = >[] } = DecorateRegistCenter aspects.forEach((aspect: IAspect): void => { aspect.setPointcuts(pointcuts, advices) }) } private createFakeInstance(component: IComponent, identi: number): PojoType{ const {cost, props, type} = component let instance!: PojoType if(type === ComponentType.DAO){ if(this.tmplDaoPool.get(identi)){ instance = this.tmplDaoPool.get(identi) }else{ instance = new cost() this.tmplDaoPool.set(identi, instance) } }else{ instance = new cost() } if(props && Array.isArray(props) && props.length > 0){ props.forEach((prop: PojoType): void => { const propName: string = Object.keys(prop)[0] const propComponent: IComponent = prop[propName] const propInstance = this.createFakeInstance(propComponent, identi) instance[propName] = propInstance }) } return instance } private handlerDevice(instance: PojoType, hitMethods: Map>, component: IComponent): void{ const methods: Array = [...hitMethods.keys()] methods.forEach(method => { const methodName = method.name const advices = > hitMethods.get(method) if(advices){ const proxy = new Proxy(method, { apply: async (target, ctx, args): Promise => { let process: any = null const beforeAdvices = > advices.filter(advice => advice.type === AdviceType.BEFORE) const afterAdvices = > advices.filter(advice => advice.type === AdviceType.AFTER) beforeAdvices.forEach(async ({type, value: handler, cost}: IAdvice) => { const joinPoint = new JoinPoint(args, handler.name, cost.name) //const aspectInstance = ContextContainer.getAspectByName(cost.name) //await aspectInstance[handler.name](joinPoint) }) if(component.packageName === 'src.service.impl.PortalService'){ const identification = Math.random() + (+ new Date()) ctx = this.createFakeInstance(component, identification) const conn = await ctx.dao.getConnection() conn.beginTransaction(async (err: MysqlError) => { if(!err){ try{ process = await Reflect.apply(target, ctx, args) conn.commit() }catch(err2){ conn.rollback() } } }) }else{ process = await Reflect.apply(target, ctx, args) } afterAdvices.forEach(async ({type, value: handler, cost}: IAdvice) => { const joinPoint = new JoinPoint(args, handler.name, cost.name) }) return process } }) instance[methodName] = proxy } }) } public matchComponent(instance: PojoType, component: IComponent): void{ const {aspects = >[]} = DecorateRegistCenter let {packageName = ''} = component const instanceMethods: Array = getInstanceMethods(instance) const hitMethods: Map> = new Map() aspects.forEach((aspect: IAspect): void => { const {pointcuts = []} = aspect pointcuts.forEach((pointcut: IPointcut): void => { const {advices, execution} = pointcut instanceMethods.forEach((method: Function) => { packageName = packageName + '.' + method.name + '()' if(execution.test(packageName)){ const existedMethod = > hitMethods.get(method) if(existedMethod){ existedMethod.push(...advices) }else{ hitMethods.set(method, advices) } } }) }) }) this.handlerDevice(instance, hitMethods, component) } }