Skip to content

Commit

Permalink
feat: refactor hook & add @app (#482)
Browse files Browse the repository at this point in the history
  • Loading branch information
kurten authored Apr 29, 2020
1 parent 89be704 commit 3bfd300
Show file tree
Hide file tree
Showing 33 changed files with 505 additions and 160 deletions.
6 changes: 0 additions & 6 deletions packages/midway-core/src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
export const MidwayHandlerKey = {
CONFIG: 'config',
PLUGIN: 'plugin',
LOGGER: 'logger',
};

export const FUNCTION_INJECT_KEY = 'midway:function_inject_key';
export const MIDWAY_ALL_CONFIG = 'midway:all_config_inject_key';

Expand Down
147 changes: 7 additions & 140 deletions packages/midway-core/src/context/midwayContainer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import * as globby from 'globby';
import {
CLASS_KEY_CONSTRUCTOR,
CONFIG_KEY,
LOGGER_KEY,
PLUGIN_KEY,
getClassMetadata,
getObjectDefinition,
getProviderId,
ObjectDefinitionOptions,
Expand All @@ -18,7 +13,7 @@ import {
import * as is from 'is-type-of';
import { join } from 'path';
import { ContainerConfiguration } from './configuration';
import { FUNCTION_INJECT_KEY, MidwayHandlerKey, MIDWAY_ALL_CONFIG } from '../common/constants';
import { FUNCTION_INJECT_KEY } from '../common/constants';
import {
IConfigService,
IEnvironmentService,
Expand All @@ -27,12 +22,14 @@ import {
MAIN_MODULE_KEY,
IContainerConfiguration,
ILifeCycle,
REQUEST_CTX_KEY,
} from '../interface';
import { MidwayConfigService } from '../service/configService';
import { MidwayEnvironmentService } from '../service/environmentService';
import { Container } from './container';
import { generateProvideId } from '../common/util';
import { pipelineFactory } from '../features/pipeline';
import { ResolverHandler } from './resolverHandler';

const DEFAULT_PATTERN = ['**/**.ts', '**/**.tsx', '**/**.js', '!**/**.d.ts'];
const DEFAULT_IGNORE_PATTERN = [
Expand All @@ -46,13 +43,8 @@ const DEFAULT_IGNORE_PATTERN = [

const debug = require('debug')('midway:container');

interface FrameworkDecoratorMetadata {
key: string;
propertyName: string;
}

export class MidwayContainer extends Container implements IMidwayContainer {
handlerMap: Map<string, (handlerKey: string, instance?: any) => any>;
resolverHandler: ResolverHandler;
// 仅仅用于兼容requestContainer的ctx
ctx = {};
readyBindModules: Map<string, Set<any>> = new Map();
Expand All @@ -70,13 +62,12 @@ export class MidwayContainer extends Container implements IMidwayContainer {
}

init(): void {
this.handlerMap = new Map();
this.initService();

this.registerEachCreatedHook();
this.resolverHandler = new ResolverHandler(this, this.getManagedResolverFactory());
// 防止直接从applicationContext.getAsync or get对象实例时依赖当前上下文信息出错
// ctx is in requestContainer
this.registerObject('ctx', this.ctx);
this.registerObject(REQUEST_CTX_KEY, this.ctx);
}

initService() {
Expand Down Expand Up @@ -200,106 +191,8 @@ export class MidwayContainer extends Container implements IMidwayContainer {
return child;
}

protected registerEachCreatedHook() {
// register constructor inject
this.beforeEachCreated((target, constructorArgs, context) => {
let constructorMetaData;
try {
constructorMetaData = getClassMetadata(CLASS_KEY_CONSTRUCTOR, target);
} catch (e) {
debug(`beforeEachCreated error ${e.stack}`);
}
// lack of field
if (constructorMetaData && constructorArgs) {
for (const idx in constructorMetaData) {
const index = parseInt(idx, 10);
const propertyMeta = constructorMetaData[index];
let result;

switch (propertyMeta.type) {
case 'config':
result = this.findHandlerHook(MidwayHandlerKey.CONFIG)(
propertyMeta.key
);
break;
case 'logger':
result = this.findHandlerHook(MidwayHandlerKey.LOGGER)(
propertyMeta.key
);
break;
case 'plugin':
result = this.findHandlerHook(MidwayHandlerKey.PLUGIN)(
propertyMeta.key
);
break;
}
constructorArgs[index] = result;
}
}
});

// register property inject
this.afterEachCreated((instance, context, definition) => {
// 处理配置装饰器
const configSetterProps: FrameworkDecoratorMetadata[] = getClassMetadata(
CONFIG_KEY,
instance
);
this.defineGetterPropertyValue(
configSetterProps,
instance,
this.findHandlerHook(MidwayHandlerKey.CONFIG)
);
// 处理插件装饰器
const pluginSetterProps: FrameworkDecoratorMetadata[] = getClassMetadata(
PLUGIN_KEY,
instance
);
this.defineGetterPropertyValue(
pluginSetterProps,
instance,
this.findHandlerHook(MidwayHandlerKey.PLUGIN)
);
// 处理日志装饰器
const loggerSetterProps: FrameworkDecoratorMetadata[] = getClassMetadata(
LOGGER_KEY,
instance
);
this.defineGetterPropertyValue(
loggerSetterProps,
instance,
this.findHandlerHook(MidwayHandlerKey.LOGGER)
);
});
}

/**
* binding getter method for decorator
*
* @param setterProps
* @param instance
* @param getterHandler
*/
private defineGetterPropertyValue(
setterProps: FrameworkDecoratorMetadata[],
instance,
getterHandler
) {
if (setterProps && getterHandler) {
for (const prop of setterProps) {
if (prop.propertyName) {
Object.defineProperty(instance, prop.propertyName, {
get: () => getterHandler(prop.key, instance),
configurable: true, // 继承对象有可能会有相同属性,这里需要配置成 true
enumerable: true,
});
}
}
}
}

registerDataHandler(handlerType: string, handler: (handlerKey) => any) {
this.handlerMap.set(handlerType, handler);
this.resolverHandler.registerHandler(handlerType, handler);
}

registerCustomBinding(objectDefinition, target) {
Expand All @@ -315,20 +208,6 @@ export class MidwayContainer extends Container implements IMidwayContainer {
}
}

/**
* get hook from current map or parent map
* @param hookKey
*/
findHandlerHook(hookKey: string) {
if (this.handlerMap.has(hookKey)) {
return this.handlerMap.get(hookKey);
}

if (this.parent) {
return (this.parent as MidwayContainer).findHandlerHook(hookKey);
}
}

createConfiguration(): IContainerConfiguration {
const containerConfiguration = new ContainerConfiguration(this);
return containerConfiguration;
Expand Down Expand Up @@ -361,18 +240,6 @@ export class MidwayContainer extends Container implements IMidwayContainer {
async ready() {
super.ready();
if (this.configService) {
// register handler for container
this.registerDataHandler(MidwayHandlerKey.CONFIG, (key: string) => {
if (key) {
if (key === MIDWAY_ALL_CONFIG) {
return this.configService.getConfiguration();
} else {
const val = this.configService.getConfiguration(key);
debug('@config key => %s value => %j.', key, val);
return val;
}
}
});
// 加载配置
await this.configService.load();
}
Expand Down
12 changes: 8 additions & 4 deletions packages/midway-core/src/context/requestContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ export class MidwayRequestContainer extends MidwayContainer {
this.registerObject(REQUEST_CTX_KEY, ctx);
// register contextLogger
this.registerObject('logger', ctx.logger);

const resolverHandler = this.applicationContext.resolverHandler;
this.beforeEachCreated(resolverHandler.beforeEachCreated.bind(resolverHandler));
this.afterEachCreated(resolverHandler.afterEachCreated.bind(resolverHandler));
}

init() {
// do nothing
}

get<T = any>(identifier: any, args?: any): T {
Expand Down Expand Up @@ -76,10 +84,6 @@ export class MidwayRequestContainer extends MidwayContainer {
}
}

initService() {
// do nothing
}

async ready() {
this.readied = true;
// ignore other things
Expand Down
132 changes: 132 additions & 0 deletions packages/midway-core/src/context/resolverHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import {
CLASS_KEY_CONSTRUCTOR,
getClassMetadata,
CONFIG_KEY,
} from '@midwayjs/decorator';
import { ManagedResolverFactory } from './managedResolverFactory';
import { MidwayContainer } from './midwayContainer';
import { MIDWAY_ALL_CONFIG } from '../common/constants';

interface FrameworkDecoratorMetadata {
key: string;
propertyName: string;
}

const debug = require('debug')('midway:container');

export type HandlerFunction = (handlerKey: string, instance?: any) => any;

export class ResolverHandler {
private handlerMap: Map<string, HandlerFunction>;
private resolverFactory: ManagedResolverFactory;
private container: MidwayContainer;

constructor(container: MidwayContainer, factory: ManagedResolverFactory) {
this.container = container;
this.resolverFactory = factory;
this.handlerMap = new Map<string, HandlerFunction>();
this.bindCreatedHook();
}

bindCreatedHook() {
this.resolverFactory.beforeEachCreated(this.beforeEachCreated.bind(this));
this.resolverFactory.afterEachCreated(this.afterEachCreated.bind(this));

if (this.container.configService) {
// register handler for container
this.registerHandler(CONFIG_KEY, (key: string) => {
if (key) {
if (key === MIDWAY_ALL_CONFIG) {
return this.container.configService.getConfiguration();
} else {
const val = this.container.configService.getConfiguration(key);
debug('@config key => %s value => %j.', key, val);
return val;
}
}
});
}
}
/**
* 创建对象前
* @param target 当前对象
* @param constructorArgs 构造参数
* @param context 上下文
*/
beforeEachCreated(target, constructorArgs: any[], context) {
let constructorMetaData;
try {
constructorMetaData = getClassMetadata(CLASS_KEY_CONSTRUCTOR, target);
} catch (e) {
debug(`beforeEachCreated error ${e.stack}`);
}
// lack of field
if (constructorMetaData && constructorArgs) {
for (const idx in constructorMetaData) {
const index = parseInt(idx, 10);
const propertyMeta = constructorMetaData[index];
const hook = this.getHandler(propertyMeta.type);
if (hook) {
constructorArgs[index] = hook(
propertyMeta.key
);
}
}
}
}
/**
* 创建对象后
* @param instance 对象
* @param context 上下文
* @param definition 定义
*/
afterEachCreated(instance, context, definition) {
const iter = this.handlerMap.keys();
for (const key of iter) {
// 处理配置装饰器
const setterProps: FrameworkDecoratorMetadata[] = getClassMetadata(
key,
instance
);
this.defineGetterPropertyValue(
setterProps,
instance,
this.getHandler(key)
);
}
}
/**
* binding getter method for decorator
*
* @param setterProps
* @param instance
* @param getterHandler
*/
private defineGetterPropertyValue(
setterProps: FrameworkDecoratorMetadata[],
instance,
getterHandler
) {
if (setterProps && getterHandler) {
for (const prop of setterProps) {
if (prop.propertyName) {
Object.defineProperty(instance, prop.propertyName, {
get: () => getterHandler(prop.key, instance),
configurable: true, // 继承对象有可能会有相同属性,这里需要配置成 true
enumerable: true,
});
}
}
}
}

registerHandler(key: string, fn: HandlerFunction) {
this.handlerMap.set(key, fn);
}

getHandler(key: string) {
if (this.handlerMap.has(key)) {
return this.handlerMap.get(key);
}
}
}
Loading

0 comments on commit 3bfd300

Please sign in to comment.