egg启动分为单进程启动和多进程启动两种方式
部分源码:
/**
* Start egg application with cluster mode
* @since 1.0.0
*/
exports.startCluster = require('egg-cluster').startCluster;
/**
* Start egg application with single process mode
* @since 1.0.0
*/
exports.start = require('./lib/start');
单进程启动:
module.exports = async (options = {}) => {
if (!options.ignoreWarning) {
console.warn('single process mode is still in experiment, please don\'t use it in production environment');
}
options.baseDir = options.baseDir || process.cwd();
options.mode = 'single';
// get agent from options.framework and package.egg.framework
if (!options.framework) {
try {
options.framework = require(path.join(options.baseDir, 'package.json')).egg.framework;
} catch (_) {
// ignore
}
}
let Agent;
let Application;
if (options.framework) {
Agent = require(options.framework).Agent;
Application = require(options.framework).Application;
} else {
Application = require('./application');
Agent = require('./agent');
}
const agent = new Agent(Object.assign({}, options));
await agent.ready();
const application = new Application(Object.assign({}, options));
application.agent = agent;
agent.application = application;
await application.ready();
// emit egg-ready message in agent and application
application.messenger.broadcast('egg-ready');
return application;
};
可以看出直接会调用 new Application(Object.assign({}, options));
多进程启动:
总括:启动过程的分析是找到总的入口文件:eggCore下的Loader是整个egg框架的入口
egg在koa框架之上进行了高度集成,进行了统一规范,在写项目的过程中,很难看出egg是怎样工作的。也就无法了解到egg的插件机制,扩展机制等是如何和koa集成。作为一名开发者仅仅掌握配置使用egg是远远不够的,本文就egg的启动过程进行了梳理,将egg的启动过程总结为一张流程图。
在egg启动过程中,主要是依赖egg-bin,egg-bin有依赖了common-bin,common-bin中又依赖了yargs,yargs-parser,有兴趣的可以自行去看yargs的文档,本文不做详细介绍。流程图如下:
简易流程:
从package.json可以看到执行npm tun dev会执行egg-bin dev
1,进到egg-bin中,会创建egg-bin实例,EggBIn实例继承自CommonBin实例,
2,接下来会执行CommonBin的load方法,将egg-bin中cmd文件夹下的启动文件放入CommonBin实例的[COMMAND](map集合)中
3,再根据命令行参数拿到对应的启动文件,执行启动文件的run方法,找到egg-cluster
4,执行egg-cluster的master方法,创建Master实例,开启App_worker子进程,Agent_worker子进程
5,App_worker子进程创建EggCore实例,并创建Loader,Lifecicle实例,Loader是egg把所有文件串起来的入口
详细流程图:里面有许多node的包,想研究的同学可以自行研究
说明:
1,这里有一个难点,this.serverBin指向了egg-bin的lib/start-cluster脚本,其中的options.framework参数从何而来,有点绕,这里的process.argv[2]正是之前cp.fork(modulePath, args, options)子进程启动时传递的参数,如果是dev,当前的process.argv[2]的值是这样的:
{
"typescript": false,
"declarations": true,
"workers": 1,
"baseDir": "项目根路径",
"port": 7002,
"framework": "项目根路径/node_modules/egg"
}
2,图中master进程启动时,会通过cfork包启动app_worker进程,cfork会在开启子进程时,传入执行文件路径,执行文件参数, agent_work通过child_process.fork实现
部分源码:egg-cluster包下文件夹lib/utils/master.js
agent_work进程
const agentWorker = childprocess.fork(this.getAgentWorkerFile(), args, opt);
app_work进程
cfork({
exec: this.getAppWorkerFile(),
args,
silent: false,
count: this.options.workers,
// don't refork in local env
refork: this.isProduction,
windowsHide: process.platform === 'win32',
});
总结:这里主要介绍了egg的启动过程,egg的核心加载流程后续介绍