Skip to content

Commit

Permalink
fix: configuration inject plugin and more in production environment (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
czy88840616 authored Oct 27, 2020
1 parent c606128 commit 41bce5d
Show file tree
Hide file tree
Showing 61 changed files with 2,132 additions and 1,249 deletions.
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@
}
},
"npmClient": "npm",
"version": "2.3.17"
"version": "2.3.18-beta.6"
}
6 changes: 3 additions & 3 deletions packages/bootstrap/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@midwayjs/bootstrap",
"version": "2.3.17",
"version": "2.3.18-beta.6",
"description": "midwayjs bootstrap",
"main": "dist/index",
"typings": "dist/index.d.ts",
Expand All @@ -22,12 +22,12 @@
"license": "MIT",
"devDependencies": {
"@midwayjs/cli": "^1.0.0",
"@midwayjs/core": "^2.3.17"
"@midwayjs/core": "^2.3.18-beta.6"
},
"author": "Harry Chen <czy88840616@gmail.com>",
"repository": {
"type": "git",
"url": "http://github.com/midwayjs/midway.git"
},
"gitHead": "44c0803552baf265debed8a11a860988b7e07a85"
"gitHead": "a603d2348d6141f8f723901498f03a162a037708"
}
6 changes: 3 additions & 3 deletions packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@midwayjs/core",
"version": "2.3.17",
"version": "2.3.18-beta.6",
"description": "midway core",
"main": "dist/index",
"typings": "dist/index.d.ts",
Expand All @@ -27,7 +27,7 @@
"sinon": "^7.2.2"
},
"dependencies": {
"@midwayjs/decorator": "^2.3.17",
"@midwayjs/decorator": "^2.3.18-beta.6",
"@midwayjs/glob": "^1.0.2",
"class-transformer": "^0.3.1",
"extend2": "^1.0.0",
Expand All @@ -48,5 +48,5 @@
"engines": {
"node": ">= 10.0.0"
},
"gitHead": "44c0803552baf265debed8a11a860988b7e07a85"
"gitHead": "a603d2348d6141f8f723901498f03a162a037708"
}
249 changes: 208 additions & 41 deletions packages/core/src/baseFramework.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
import {
IConfigurationOptions,
ILifeCycle,
IMidwayApplication,
IMidwayBootstrapOptions,
IMidwayContainer,
IMidwayFramework,
MidwayFrameworkType,
MidwayProcessTypeEnum,
} from './interface';
import { ContainerLoader } from './';
import { APPLICATION_KEY } from '@midwayjs/decorator';
import { MidwayContainer } from './context/midwayContainer';
import {
APPLICATION_KEY,
ASPECT_KEY,
CONFIGURATION_KEY,
getClassMetadata,
getProviderId,
IMethodAspect,
listModule,
listPreloadModule,
} from '@midwayjs/decorator';
import { isAbsolute, join } from 'path';

function buildLoadDir(baseDir, dir) {
if (!isAbsolute(dir)) {
return join(baseDir, dir);
}
return dir;
}

export abstract class BaseFramework<
APP extends IMidwayApplication,
Expand All @@ -17,7 +35,7 @@ export abstract class BaseFramework<
protected isTsMode = true;
protected baseDir: string;
protected appDir: string;
protected containerLoader: ContainerLoader;
protected applicationContext: IMidwayContainer;
public configurationOptions: T;
public app: APP;

Expand All @@ -26,54 +44,113 @@ export abstract class BaseFramework<
return this;
}

public async initialize(
options: Partial<IMidwayBootstrapOptions>
): Promise<void> {
public async initialize(options: IMidwayBootstrapOptions): Promise<void> {
this.baseDir = options.baseDir;
this.appDir = options.appDir;

this.containerLoader = new ContainerLoader({
baseDir: this.baseDir,
isTsMode: this.isTsMode,
preloadModules: options.preloadModules || [],
});
/**
* before create MidwayContainer instance,can change init parameters
*/
await this.beforeContainerInitialize(options);

/**
* initialize containerLoader and initialize ioc container instance
* initialize MidwayContainer instance
*/
await this.beforeInitialize(options);
this.containerLoader.initialize();
await this.containerInitialize(options);

/**
* before container load directory and bind
*/
await this.afterContainerInitialize(options);

/**
* run container loadDirectoryLoad method to create object definition
*/
await this.containerDirectoryLoad(options);

/**
* after container load directory and bind
*/
await this.afterContainerDirectoryLoad(options);

/**
* Third party application initialization
*/
await this.applicationInitialize(options);

/**
* start to load configuration and lifeCycle
*/
await this.containerReady(options);

/**
* after container refresh
*/
await this.afterContainerReady(options);
}

protected async containerInitialize(options: IMidwayBootstrapOptions) {
this.applicationContext = new MidwayContainer(this.baseDir, undefined);
this.applicationContext.disableConflictCheck =
options.disableConflictCheck || true;
this.applicationContext.registerObject('baseDir', this.baseDir);
this.applicationContext.registerObject('appDir', this.appDir);
this.applicationContext.registerObject('isTsMode', this.isTsMode);
}

protected async containerDirectoryLoad(options: IMidwayBootstrapOptions) {
/**
* load directory and bind files to ioc container
*/
await this.beforeDirectoryLoad(options);
const applicationContext = this.containerLoader.getApplicationContext();
applicationContext.registerObject('baseDir', this.baseDir);
applicationContext.registerObject('appDir', this.appDir);
// 如果没有关闭autoLoad 则进行load
this.containerLoader.loadDirectory(options);

// register app
this.containerLoader.registerHook(APPLICATION_KEY, () => {
return this.getApplication();
if (!this.isTsMode && options.disableAutoLoad === undefined) {
// disable auto load in js mode by default
options.disableAutoLoad = true;
}

if (options.disableAutoLoad) return;

// use baseDir in parameter first
const baseDir = options.baseDir || this.baseDir;
const defaultLoadDir = this.isTsMode ? [baseDir] : [];
this.applicationContext.load({
loadDir: (options.loadDir || defaultLoadDir).map(dir => {
return buildLoadDir(baseDir, dir);
}),
pattern: options.pattern,
ignore: options.ignore,
});

await this.afterDirectoryLoad(options);
if (options.preloadModules && options.preloadModules.length) {
for (const preloadModule of options.preloadModules) {
this.applicationContext.bindClass(preloadModule);
}
}

this.applicationContext.registerDataHandler(APPLICATION_KEY, () => {
return this.getApplication();
});
}

protected async containerReady(options: IMidwayBootstrapOptions) {
if (!this.app.getApplicationContext) {
this.app = this.defineApplicationProperties(this.app);
this.defineApplicationProperties();
}

/**
* start to load configuration and lifeCycle
*/
await this.containerLoader.refresh();
await this.afterInitialize(options);
await this.applicationContext.ready();
// lifecycle 支持
await this.loadLifeCycles();
// 预加载模块支持
await this.loadPreloadModule();
// 切面支持
await this.loadAspect();
}

protected async containerStop() {
await this.applicationContext.stop();
}

public getApplicationContext(): IMidwayContainer {
return this.containerLoader.getApplicationContext();
return this.applicationContext;
}

public getConfiguration(key?: string): any {
Expand All @@ -88,6 +165,8 @@ export abstract class BaseFramework<
.getCurrentEnvironment();
}

public abstract async applicationInitialize(options: IMidwayBootstrapOptions);

public abstract getFrameworkType(): MidwayFrameworkType;

public abstract getApplication(): APP;
Expand All @@ -96,11 +175,11 @@ export abstract class BaseFramework<

public async stop(): Promise<void> {
await this.beforeStop();
await this.containerLoader.stop();
await this.containerStop();
}

protected defineApplicationProperties(app: APP): APP {
return Object.assign(app, {
protected defineApplicationProperties(applicationProperties: object = {}) {
const defaultApplicationProperties = {
getBaseDir: () => {
return this.baseDir;
},
Expand All @@ -115,6 +194,10 @@ export abstract class BaseFramework<
.getCurrentEnvironment();
},

getApplicationContext: () => {
return this.getApplicationContext();
},

getConfig: (key?: string) => {
return this.getApplicationContext()
.getConfigService()
Expand All @@ -128,24 +211,108 @@ export abstract class BaseFramework<
getProcessType: () => {
return MidwayProcessTypeEnum.APPLICATION;
},
});
};
Object.assign(
this.app,
defaultApplicationProperties,
applicationProperties
);
}

protected async beforeStop(): Promise<void> {}

protected async beforeInitialize(
protected async beforeContainerInitialize(
options: Partial<IMidwayBootstrapOptions>
): Promise<void> {}

protected async beforeDirectoryLoad(
protected async afterContainerInitialize(
options: Partial<IMidwayBootstrapOptions>
): Promise<void> {}

protected async afterDirectoryLoad(
protected async afterContainerDirectoryLoad(
options: Partial<IMidwayBootstrapOptions>
): Promise<void> {}

protected abstract async afterInitialize(
protected async afterContainerReady(
options: Partial<IMidwayBootstrapOptions>
): Promise<void>;
): Promise<void> {}

public async loadLifeCycles() {
// agent 不加载生命周期
if (this.app.getProcessType() === MidwayProcessTypeEnum.AGENT) return;
const cycles: Array<{ target: any; namespace: string }> = listModule(
CONFIGURATION_KEY
);
for (const cycle of cycles) {
const providerId = getProviderId(cycle.target);
const inst = await this.getApplicationContext().getAsync<ILifeCycle>(
providerId
);
if (typeof inst.onReady === 'function') {
/**
* 让组件能正确获取到 bind 之后 registerObject 的对象有三个方法
* 1、在 load 之后修改 bind,不太可行
* 2、每次 getAsync 的时候,去掉 namespace,同时还要查找当前全局的变量,性能差
* 3、一般只会在 onReady 的地方执行 registerObject(否则没有全局的意义),这个取巧的办法就是 onReady 传入一个代理,其中绑定当前的 namespace
*/
await inst.onReady(
new Proxy(this.getApplicationContext(), {
get: function (target, prop, receiver) {
if (prop === 'getCurrentNamespace' && cycle.namespace) {
return () => {
return cycle.namespace;
};
}
return Reflect.get(target, prop, receiver);
},
})
);
}
}
}

/**
* load preload module for container
* @private
*/
private async loadPreloadModule() {
// some common decorator implementation
const modules = listPreloadModule();
for (const module of modules) {
// preload init context
await this.getApplicationContext().getAsync(module);
}
}

/**
* load aspect method for container
* @private
*/
private async loadAspect() {
// for aop implementation
const aspectModules = listModule(ASPECT_KEY);
// sort for aspect target
let aspectDataList = [];
for (const module of aspectModules) {
const data = getClassMetadata(ASPECT_KEY, module);
aspectDataList = aspectDataList.concat(
data.map(el => {
el.aspectModule = module;
return el;
})
);
}

// sort priority
aspectDataList.sort((pre, next) => {
return (next.priority || 0) - (pre.priority || 0);
});

for (const aspectData of aspectDataList) {
const aspectIns = await this.getApplicationContext().getAsync<
IMethodAspect
>(aspectData.aspectModule);
await this.getApplicationContext().addAspect(aspectIns, aspectData);
}
}
}
Loading

0 comments on commit 41bce5d

Please sign in to comment.