Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: refactor hook & add @App #482

Merged
merged 2 commits into from
Apr 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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