动态函数注入

动态函数注入

在某些场景下,我们需要函数作为某个逻辑动态执行,而 IoC 中的对象属性则都是已经创建好的,无法满足动态的逻辑需求。

比如你需要一个工厂函数,根据不同的场景返回不同的实例,也可能有一个三方包,是个函数,在业务中想要直接调用,种种的场景下,你就需要直接注入一个函数,并且在函数中拿到上下文。

标准的函数注入样例。

export function contextHandler(context) {
  return async () => {
    // const xxx = context.getAsync('xxxx');
    return true;
  };
}

providerWrapper([
  {
    id: 'contextHandler',
    provider: contextHandler,
  }
]);

使用端。

@provide()
export class BaseService {

  @inject()
  contextHandler: () => boolean;

}

midway 通过 providerWrapper 函数来包裹一个函数,并且指定提供的 key,供其他 IoC 对象使用。由于函数直接传递了一个 context 对象,可以轻松的通过此对象拿到所需的其他对象,而不需要管理依赖。

函数注入大多数为了创建一个简单的工厂。

export function adapterFactory(context: IApplicationContext) {
  return async (adapterName: string) => {
    if (adapterName === 'google') {
      return await context.getAsync('googleAdapter');
    }

    if (adapterName === 'baidu') {
      return await context.getAsync('baiduAdapter');
    }

    // return await context.getAsync(adapterName + 'Adapter');
  };
}

providerWrapper([
  {
    id: 'adapterFactory',
    provider: adapterFactory,
  }
]);

这样在业务中,可以直接来使用了。


@provide()
export class BaseService {

  @config('adapterName')
  adapterName;

  @inject('adapterFactory')
  factory;

  adapter: Adapter;

  @init()
  async init() {
    this.adapter = await this.factory(this.adapterName);
  }

}

TIP

这个函数可以是异步的 (async)。

再举个例子,比如如果应用希望自己使用 sequelize, 而 sequelize 的创建 model 的过程是个异步操作,代码就可以这么写:

import { providerWrapper, IApplicationContext } from 'midway';
import * as Sequelize from 'sequelize';
import { Sequelize as SequelizeInstance } from 'sequelize';

// 可以直接写 async 方法
export async function factory(context: IApplicationContext) {

  const instance = await context.getAsync<SequelizeInstance>('coreDB');

  const UiKeyTraceModel = instance.define(name, {
    gmtCreate: {
      type: Sequelize.DATE,
      allowNull: true,
      field: 'gmt_create',
    },
    gmtModified: {
      type: Sequelize.DATE,
      allowNull: true,
      field: 'gmt_modified',
    }
  }, {
    timestamps: true,
    createdAt: 'gmt_create',
    updatedAt: 'gmt_modified',
    freezeTableName: true,
    tableName: 'xxxx'
  });

  return UiKeyTraceModel;
}

providerWrapper([
  {
    id: 'keyTraceModel',
    provider: factory
  }
]);

通过 providerWrapper 我们将一个原本的函数写法进行了包裹,和现有的依赖注入体系可以融合到一起,让容器能够统一管理。