pomelo源码解析(总结)

这是pomelo源码分析的最后一篇文章。讲一下典型的一个pomelo引擎做了什么

从哪里启动的

我们知道一个pomelo启动是这样子的pomelo start
可以看下电脑的环境变量,最终执行文件在pomelo/bin/pomelo

program.command('start')
  .description('start the application')
  .option('-e, --env <env>', 'the used environment', DEFAULT_ENV)
  .option('-D, --daemon', 'enable the daemon start')
  .option('-d, --directory, <directory>', 'the code directory', DEFAULT_GAME_SERVER_DIR)
  .option('-t, --type <server-type>,', 'start server type')
  .option('-i, --id <server-id>', 'start server id')
  .action(function(opts) {
    start(opts);
  });

写入一些启动参数,这里只是写入了执行环境以及目录地址
在start函数中很简单,检测一些文件。
写入执行环境以及服务器类型,然后启动目录下的app.js文件
转过来看app.js干了什么
第一行var pomelo = require(‘pomelo’);
生成一个pomelo对象,pomelo对象有什么

createApp做了什么

生成pomelo对象后,紧接着创建了一个app

var app = pomelo.createApp();

跳转到application.js中生成一个实体。
在Application.init中存有一些内部变量可以自己研究,这里分析下appUtil.defaultConfiguration(this);

module.exports.defaultConfiguration = function(app) {
  var args = parseArgs(process.argv);
  setupEnv(app, args);
  loadMaster(app);
  loadServers(app);
  processArgs(app, args);
  configLogger(app);
  loadLifecycle(app);
};

setupEnv(app, args); // 根据启动参数设置环境变量
loadMaster(app); // 载入master配置 /config/master.json存入app.master
loadServers(app); // 载入servers配置 /config/servers.json存入app.__serverMap__
processArgs(app, args); // 根据启动参数设置到app中的属性中。这里需要注意下,启动参数中如果没有写入serverId,默认会是master的id,也就是第一个进程启动的是master
configLogger(app); // log配置
oadLifecycle(app); // 启动进程的生命期 读取app/servers/serverName/lifecycle.js,对进程启动前,启动后,关闭可以触发回调函数

configure做了什么

Application.configure = function (env, type, fn) {
  var args = [].slice.call(arguments);
  fn = args.pop();
  env = type = Constants.RESERVED.ALL;

  if(args.length > 0) {
    env = args[0];
  }
  if(args.length > 1) {
    type = args[1];
  }

  if (env === Constants.RESERVED.ALL || contains(this.settings.env, env)) {
    if (type === Constants.RESERVED.ALL || contains(this.settings.serverType, type)) {
      fn.call(this);
    }
  }
  return this;
};

可以看到,通过传入的env或者type,来决定是否执行传入的回调函数
转过来看app.js中的代码

app.configure('production|development', 'connector', function(){
  app.set('connectorConfig',
    {
      connector : pomelo.connectors.hybridconnector,
      heartbeat : 3,
      useDict : true,
      useProtobuf : true
    });
});

这里就是当环境为’production|development’且进程为’connector’执行里面的函数

这里可以处理特定进程的一些特定操作。这个代码中就是设置了一些connector进程的’connectorConfig’参数,这个参数干什么的,往下看。

start做了什么

app.start();

在 Application.start中,我们看下。
appUtil.startByType
这里是根据传入的参数启动,startId和type
在本例中startByType仅仅是执行回调。

appUtil.loadDefaultComponents(self)
这里可以看到。因为是master进程,所以取了masterConfig属性,当作参数生成一个master组件
组件看这里
然后启动了一个monitor组件,没错master进程做到了自己监控自己

在Application.load函数中,会把加载的组件写入this.loaded

接下来是调用进程的生命期的before函数,之后执行startUp
appUtil.optComponents
在这里执行各个组件的start函数,正式启动组件
然后就是进入Application.afterStart
先执行各个组件的‘afterStart’函数,然后是进程生命期的after

其他进程怎么启动的?

在master组件启动中pomelo/lib/master/master.js start

if(self.app.get(Constants.RESERVED.MODE) !== Constants.RESERVED.STAND_ALONE) {
        starter.runServers(self.app);
      }

当目前的模式不是单进程模式时,会调用一次runServers

 starter.runServers = function(app) {
  var server, servers;
  var condition = app.startId || app.type;
  switch(condition) {
    case Constants.RESERVED.MASTER:
    break;
    case Constants.RESERVED.ALL:
    servers = app.getServersFromConfig();
    for (var serverId in servers) {
      this.run(app, servers[serverId]);
    }
    break;
    default:
    server = app.getServerFromConfig(condition);
    if(!!server) {
      this.run(app, server);
    } else {
      servers = app.get(Constants.RESERVED.SERVERS)[condition];
      for(var i=0; i<servers.length; i++) {
        this.run(app, servers[i]);
      }
    }
  }
};

我们第一次启动时基本也没什么参数,可以自己打断点看下参数。这里的condition=ALL
拉去server的所有配置,然后run一下
在run里面的,设置了一堆奇奇怪怪的参数,然后启动进程,依旧是执行app.js

其他进程的start做了什么

configure不说了,就是一些特殊操作,本例中就是设置了’connectorConfig’属性
appUtil.startByType
仅仅是回调,同上

appUtil.loadDefaultComponents(self)
在这里可以看到,对于非master进程来说,启动了很多的组件。前端和后端启动的也有点差别。
注意:在加载组件的时候,入参就是设置在app上的属性。例如本例中在app.configure中设置了‘connectorConfig’属性,这个属性在app.load(pomelo.connector, app.get('connectorConfig'));
这里就用到了。

所以说当你需要一些特殊处理的组件时,可以在app.configure中做对应的设置

appUtil.optComponents
启动加载好的组件。

总结

pomelo的整体源码分析已经完成了。这种组件化的方式挺好的。js语言比较简单,没有奇奇怪怪的黑魔法,所以整体看下来挺顺畅的。
复杂的就是通信的组件,因为兼容了几种方式。

猜你喜欢

转载自blog.csdn.net/qq_37543025/article/details/86109465