Aller au contenu principal
Version: 3.0.0

Life cycle

Under normal circumstances, we want to do some initialization or other pre-processing things when the application starts, such as creating a database connection and pre-generating some configuration, instead of processing it when requesting a response.

Project life cycle

The framework provides these lifecycle functions for developers to handle:

  • Configuration file loading, we can modify the configuration here (onConfigLoad)
  • When the dependent injection container is ready, most things can be done at this stage (onReady)
  • After the service is started, you can get the server( onServerReady)
  • The application is about to be shut down. Here, clean up the resources (onStop ).

Midway's life cycle is to implement the ILifeCycle interface through the src/configuration.ts file, which can be automatically loaded when the project starts.

The interface is defined as follows.

interface ILifeCycle {
/**
* Execute after the application configuration is loaded
*/
onConfigLoad?(container: IMidwayContainer, app: IMidwayApplication): Promise<void>;

/**
* Execute when relying on the injection container ready
*/
onReady(container: IMidwayContainer, app: IMidwayApplication): Promise<void>;

/**
* Execute after the application service is started
*/
onServerReady?(container: IMidwayContainer, app: IMidwayApplication): Promise<void>;

/**
* Execute when the application stops
*/
onStop?(container: IMidwayContainer, app: IMidwayApplication): Promise<void>;
}

onConfigLoad

Generally used to modify the configuration file of the project.

For example.

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core';

@Configuration()
export class MainConfiguration implements ILifeCycle {

async onConfigLoad(): Promise<void> {
// The data returned directly will be automatically merged into the configuration.
return {
test: 1
}
}
}

In this case, the @Config configuration contains the returned data. For more information, see [Asynchronous initialization configuration](./env_config# Asynchronous Initialization Configuration).

onReady

onReady is a life cycle that is used in most scenarios.

info

Note that ready here refers to the dependency injection container ready, not the application ready, so you can make any extension to the application, such as adding middleware, connecting databases, etc.

We need to connect a database in advance during initialization. Since it is in the class, we can also inject the connection tool class of a database such as db through the @Inject decorator. This instance contains two functions, connect and close:

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core';

@Configuration()
export class MainConfiguration implements ILifeCycle {
@Inject()
db: any;

async onReady(container: IMidwayContainer): Promise<void> {
// Establish a database connection
await this.db.connect();
}

async onStop(): Promise<void> {
// Close database connection
await this.db.close();
}
}

In this way, we can establish the database connection when the application starts, rather than creating it when the response is requested. At the same time, when the application is stopped, the database connection can also be closed gracefully.

In addition, in this way, the default injected objects can be expanded.

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core';
import * as sequelize from 'sequelize';

@Configuration()
export class MainConfiguration implements ILifeCycle {

async onReady(container: IMidwayContainer): Promise<void> {
// Three-party package object
container.registerObject('sequelize', sequelize);
}
}

It can be directly injected into other classes.

export class IndexHandler {

@Inject()
sequelize;

async handler() {
console.log(this.sequelize);
}
}

onServerReady

This lifecycle is needed when you want to get information about the framework's service objects, ports, and so on.

Let's take @midwayjs/koa as an example to get its Server at startup.

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core';
import * as koa from '@midwayjs/koa';

@Configuration({
imports: [koa]
})
export class MainConfiguration implements ILifeCycle {

async onServerReady(container: IMidwayContainer): Promise<void> {
// Obtain the exposed Framework in koa
const framework = await container.getAsync(koa.Framework);
const server = framework.getServer();
// ...

}
}

onStop

We can clean up some resources at this stage, such as closing the connection.

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer } from '@midwayjs/core';
import * as koa from '@midwayjs/koa';

@Configuration({
imports: [koa]
})
export class MainConfiguration implements ILifeCycle {
@Inject()
db: any;

async onReady(container: IMidwayContainer): Promise<void> {
// Establish a database connection
await this.db.connect();
}

async onStop(): Promise<void> {
// Close database connection
await this.db.close();
}
}

onHealthCheck

When the built-in health check service calls the status retrieval API, this method is automatically executed for all components.

The following simulates a db health check method.

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer, HealthResult } from '@midwayjs/core';

@Configuration({
namespace: 'db'
})
export class MainConfiguration implements ILifeCycle {
@Inject()
db: any;

async onReady(container: IMidwayContainer): Promise<void> {
await this.db.connect();
}

async onHealthCheck(): Promise<HealthResult> {
try {
const result = await this.db.isConnect();
if (result) {
return {
status: true,
};
} else {
return {
status: false,
reason: 'db is disconnected',
};
}
} catch (err) {
return {
status: false,
reason: err.message,
};
}
}
}

In the above onHealthCheck, a status check of isConnect is called, and a fixed HealthResult type format is returned based on the result.

Note that external calls to onHealthCheck may be very frequent. Please keep the check logic as reliable and efficient as possible to ensure that there is no greater pressure on check dependencies. At the same time, please handle the logic of resource release after the check timeout by yourself to avoid the risk of memory leaks caused by frequent resource requests without returning results.

Global Object Lifecycle

The so-called object life cycle refers to the event that each object is created and destroyed in the dependency injection container. Through these life cycles, we can do some operations when the object is created and destroyed.

export interface IObjectLifeCycle {
onBeforeObjectCreated(/**...**/);
onObjectCreated(/**...**/);
onObjectInit(/**...**/);
onBeforeObjectDestroy(/**...**/);
}

These stages are already included in the ILifeCycle definition.

attention

Note that the object lifecycle API will affect the entire dependency injection container and the use of the business. Please operate with caution.

onBeforeObjectCreated

Before the business object instance is created, some objects inside the framework cannot be intercepted because they have been initialized.

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer, ObjectBeforeCreatedOptions } from '@midwayjs/core';

@Configuration()
export class MainConfiguration implements ILifeCycle {

async onBeforeObjectCreated(Clzz: new (...args), options: ObjectBeforeCreatedOptions): Promise<void> {
// ...
}
}

There are two parameters in the entry parameter:

  • Clzz is the prototype class of the object to be created.
  • options some parameters

The parameters are as follows:

PropertyTypeDescription
options.contextIMidwayContainerDependent injection container itself
options.definitionIObjectDefinitionObject definition
options.constructorArgsany[]Constructor input parameter

onObjectCreated

Execute after the object instance is created, this stage can replace the created object.

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer, ObjectCreatedOptions } from '@midwayjs/core';

@Configuration()
export class MainConfiguration implements ILifeCycle {

async onObjectCreated(ins: any, options: ObjectCreatedOptions): Promise<void> {
// ...
}
}

There are two parameters in the entry parameter:

  • ins is the object created by the builder.
  • options some parameters

The parameters are as follows:

PropertyTypeDescription
options.contextIMidwayContainerDependent injection container itself
options.definitionIObjectDefinitionObject definition
options.replaceCallback(ins: any) => voidCallback method for object replacement

Example: dynamically add attributes

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from '@midwayjs/core';

@Configuration()
export class MainConfiguration implements ILifeCycle {

async onObjectCreated(ins: any, options: ObjectInitOptions): Promise<void> {
// Each created object will add a_name attribute
ins._name = 'xxxx';
// ...
}
}

Example: Replace an object

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from '@midwayjs/core';

@Configuration()
export class MainConfiguration implements ILifeCycle {

async onObjectCreated(ins: any, options: ObjectInitOptions): Promise<void> {
// Each created object will be replaced with {bbb: 'aaa'}
options.replaceCallback({
bbb: 'aaa'
});

// ...
}
}

onObjectInit

Execute after the asynchronous initialization method is executed after the object instance is created.

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer, ObjectInitOptions } from '@midwayjs/core';

@Configuration()
export class MainConfiguration implements ILifeCycle {

async onObjectInit(ins: any, options: ObjectInitOptions): Promise<void> {
// ...
}
}

There are two parameters in the entry parameter:

  • ins is the object created by the builder.
  • options some parameters

The parameters are as follows:

PropertyTypeDescription
options.contextIMidwayContainerDependent injection container itself
options.definitionIObjectDefinitionObject definition
info

At this stage, you can also dynamically attach attributes, methods, etc. to objects. The difference with onObjectCreated is that this stage is after the initialization method is executed.

onBeforeObjectDestroy

Execute before the object instance is destroyed.

// src/configuration.ts
import { Configuration, ILifeCycle, IMidwayContainer, ObjectBeforeDestroyOptions } from '@midwayjs/core';

@Configuration()
export class MainConfiguration implements ILifeCycle {

async onBeforeObjectDestroy(ins: any, options: ObjectBeforeDestroyOptions): Promise<void> {
// ...
}
}

There are two parameters in the entry parameter:

  • ins is the object created by the builder.
  • options some parameters

The parameters are as follows:

PropertyTypeDescription
options.contextIMidwayContainerDependent injection container itself
options.definitionIObjectDefinitionObject definition