AOP是什么

Spring中AOP是面向切面编程。EggBornJS同样也实现了AOP机制,可以对Bean组件进行逻辑扩展

定义AOP

由于AOP也是一种Bean,因此也有两种定义模式:app和ctx。下面以ctx模式为例

src/module/test-party/backend/src/aop/regExp.js

module.exports = ctx => {
  class regExpAop {

    get__name(context, next) {
      next();
      context.value = `${context.value}:regexpaop`;
    }

    set__name(context, next) {
      const parts = context.value.split(':');
      const index = parts.indexOf('regexpaop');
      if (index > -1) {
        parts.splice(index, 1);
      }
      context.value = parts.join(':');
      next();
    }

    actionSync(context, next) {
      next();
      context.result = `${context.result}:regexpaop`;
    }

    async actionAsync(context, next) {
      await next();
      context.result = `${context.result}:regexpaop`;
    }

  }

  return regExpAop;
};

1. 属性AOP

在对Bean属性进行AOP时,需要创建两个方法,使用约定的前缀: get__set__

名称 说明
context Bean属性的环境参数
next 由于Bean组件可以挂载多个AOP,形成AOP调用链,因此需要调用next让调用链可以继续,类似于KOA的洋葱圈模型
  • context
名称 说明
target Bean实例
receiver Bean的Proxy实例
prop Bean实例的属性名
method AOP当前被调用的方法名
value 属性值

2. 方法AOP

在对Bean方法进行AOP时,方法名保持不变,但是需要采用约定的传参格式

名称 说明
context Bean方法的环境参数
next 由于Bean组件可以挂载多个AOP,形成AOP调用链,因此需要调用next让调用链可以继续,类似于KOA的洋葱圈模型
  • context
名称 说明
target Bean实例
receiver Bean的Proxy实例
prop Bean实例的方法名
arguments Bean方法的实际传参
result Bean方法的计算结果,最终作为返回值

洋葱圈模型与5种AOP通知类型

Spring的AOP有5种通知类型,分别是:@Before、@After、@AfterReturning、@AfterThrowing、@Around

而EggBornJS中的AOP采用洋葱圈模型,只需一种方式即可同时支持Spring的5种AOP通知类型

注册AOP

AOP的注册方式与Bean类似

src/module/test-party/backend/src/aops.js

const regExp = require('./aop/regExp.js');
const simple = require('./aop/simple.js');

module.exports = app => {
  const aops = {};
  if (app.meta.isTest || app.meta.isLocal) {
    Object.assign(aops, {
      simple: {
        match: 'testctx',
        mode: 'ctx',
        bean: simple,
      },
      regExp: {
        match: [ /^test-party.test\.\w+$/, 'testctx' ],
        mode: 'ctx',
        bean: regExp,
      },
    });
  }

  return aops;
};
名称 说明
mode 模式:app/ctx
bean aop组件(也是一种Bean组件)
match 匹配beanFullName
  • match可以设置如下类型
    1. String: 精确匹配beanFullName
    2. RegExp: 按RegExp对beanFullName进行匹配测试
    3. Array[String/RegExp]: 任何一个匹配通过即可