pomelo之application的创建于初始化



这一篇来写pomelo的application的创建过程。。当然例子还是以官方的chat。。。。主要是来分析下面这段代码:

[javascript] view plain copy print ?
  1. var app = pomelo.createApp();  

我们首先来看看pomelo的定义吧:

[javascript] view plain copy print ?
  1. var fs = require('fs');  
  2. var path = require('path');  
  3. var application = require('./application');  
  4.   
  5.   
  6. /** 
  7.  * Expose `createApplication()`. 
  8.  * 
  9.  * @module 
  10.  */  
  11. //这里相当于是进行命名  
  12. var Pomelo = module.exports = {};  
  13.   
  14. /** 
  15.  * Framework version. 
  16.  */  
  17.   
  18. Pomelo.version = '0.4';  
  19.   
  20. /** 
  21.  * Event definitions that would be emitted by app.event 
  22.  */  
  23. Pomelo.events = require('./util/events');  
  24.   
  25. /** 
  26.  * auto loaded components 
  27.  */  
  28.  //用于保存组件  
  29. Pomelo.components = {};  
  30.   
  31. /** 
  32.  * auto loaded filters 
  33.  */  
  34.  //用于保存filter  
  35. Pomelo.filters = {};  
  36.   
  37. /** 
  38.  * connectors 
  39.  */  
  40.  //connector对象  
  41. Pomelo.connectors = {};  
  42. //connector对象的get方法  
  43. Pomelo.connectors.__defineGetter__('sioconnector'function() {  
  44.   return require('./connectors/sioconnector');  
  45. });  
  46. //超级connector的get方法  
  47. Pomelo.connectors.__defineGetter__('hybridconnector'function() {  
  48.   return require('./connectors/hybridconnector');  
  49. });  
  50.   
  51. /** 
  52.  * schedulers 
  53.  */  
  54.  //定义调度器  
  55. Pomelo.schedulers = {};  
  56. Pomelo.schedulers.__defineGetter__('direct'function() {  
  57.   var m = require('./scheduler/direct');  
  58.   return m;  
  59. });  
  60.   
  61. Pomelo.schedulers.__defineGetter__('buffer'function() {  
  62.   return require('./scheduler/buffer');  
  63. });  
  64.   
  65. /** 
  66.  * global channel manager 
  67.  */  
  68. Pomelo.connectors.__defineGetter__('redisGlobalChannelManager'function() {  
  69.   return require('./common/manager/redisGlobalChannelManager');  
  70. });  
  71.   
  72. //用self来指向当前的作用域  
  73. var self = this;  
  74.   
  75. /** 
  76.  * Create an pomelo application. 
  77.  * 
  78.  * @return {Application} 
  79.  * @memberOf Pomelo 
  80.  * @api public 
  81.  */  
  82.  //创建application对象  
  83. Pomelo.createApp = function (opts) {  
  84.   var app = application;  
  85.   app.init(opts);  //初始化函数  
  86.   self.app = app;  
  87.   return app;  
  88. };  
  89.   
  90. /** 
  91.  * Get application 
  92.  */  
  93.  //相当于是为Pomelo对象添加一个属性,app,它是一个对象,就存在一个get方法,用于返回当前的app对象  
  94. Object.defineProperty(Pomelo, 'app', {  
  95.   get:function () {  
  96.     return self.app;  
  97.   }  
  98. });  
  99.   
  100. /** 
  101.  * Auto-load bundled components with getters. 
  102.  */  
  103.  //用于在components文件夹中读取组件,然后保存到components对象里面去  
  104. fs.readdirSync(__dirname + '/components').forEach(function (filename) {  
  105.   if (!/\.js$/.test(filename)) {  
  106.     return;  
  107.   }  
  108.   var name = path.basename(filename, '.js');  
  109.   
  110.   function load() {  
  111.     return require('./components/' + name);  
  112.   }  
  113.   Pomelo.components.__defineGetter__(name, load);//例如执行Pomelo.components.aa,其实会得到require("./components/aa");的值  
  114.   Pomelo.__defineGetter__(name, load);  
  115. });  
  116.   
  117. //用于读取filter对象  
  118. fs.readdirSync(__dirname + '/filters/handler').forEach(function (filename) {  
  119.   if (!/\.js$/.test(filename)) {  
  120.     return;  
  121.   }  
  122.   var name = path.basename(filename, '.js');  
  123.   
  124.   function load() {  
  125.     return require('./filters/handler/' + name);  
  126.   }  
  127.   Pomelo.filters.__defineGetter__(name, load);  
  128.   Pomelo.__defineGetter__(name, load);  
  129. });  
其实本身pomelo的定义还是很简单的,无非就是定义了一些名字,然后加载了一些组件,这里其实可以将pomelo对象看成已是一个资源的管理。。。

这里大量用到了如下的方法:

[javascript] view plain copy print ?
  1. Pomelo.connectors.__defineGetter__('redisGlobalChannelManager'function() {  
  2.   return require('./common/manager/redisGlobalChannelManager');  
  3. });  
这种用法其实就是定义一下这个属性的获取方法,当Pomelo.connectors.redisGlobalChannelManager的方式访问这个属性的时候,会直接调用换进去的函数,得到返回值。。。

我们重点来分析如下代码:

[javascript] view plain copy print ?
  1.  //创建application对象  
  2. Pomelo.createApp = function (opts) {  
  3.   var app = application;  
  4.   app.init(opts);  //初始化函数  
  5.   self.app = app;  
  6.   return app;  
  7. };  
由于application的定义比较长,就不一次性列出来,先来看看它的init方法。。。。
[javascript] view plain copy print ?
  1. Application.init = function(opts) {  
  2.   opts = opts || {};  
  3.   this.loaded = [];       // loaded component list  
  4.   //用于保存所有的组件  
  5.   this.components = {};   // name -> component map  
  6.   
  7.   //调用set方法保存的参数将会保存在这个地方  
  8.   this.settings = {};     // collection keep set/get  
  9.   this.set('base', opts.base);  
  10.   //事件对象  
  11.   this.event = new EventEmitter();  // event object to sub/pub events  
  12.   
  13.   // current server info  
  14.   this.serverId = null;   // current server id  
  15.   this.serverType = null// current server type  
  16.   this.curServer = null;  // current server info  
  17.   
  18.   // global server infos  
  19.   this.master = null;         // master server info  
  20.   //用于保存所有的server,id与info的键值对  
  21.   this.servers = {};          // current global server info maps, id -> info  
  22.   this.serverTypeMaps = {};   // current global type maps, type -> [info]  
  23.   this.serverTypes = [];      // current global server type list  
  24.   
  25.   appUtil.defaultConfiguration(this);   //默认配置  
  26.   
  27.   this.state = STATE_INITED;  //将当前的状态修改为已经初始化  
  28.   logger.info('application inited: %j'this.getServerId());  
  29. };  
刚开始启动的视乎,没有参数传进来,opts就是null,代码本身也很简单吧,可以当做是对application对象的一些属性的声明和初始化。。。

这里主要是要看一下defaultConfiguration部分干了些什么。。。

我们来看看它的定义吧:

[javascript] view plain copy print ?
  1. module.exports.defaultConfiguration = function (app) {  
  2.   var args = parseArgs(process.argv);  //这里process.argv保存的是运行使用的命令,是一个数组例如[ 'node', '/home/fjs/Desktop/pomelo/game-server/app.js' ]  
  3.   /* 
  4.   [ '/usr/local/bin/node', 
  5.   '/home/fjs/Desktop/pomelo/game-server/app.js', 
  6.   'env=development', 
  7.   'id=chat-server-2', 
  8.   'host=127.0.0.1', 
  9.   'port=6051', 
  10.   'serverType=chat' ] 
  11. */  
  12.   
  13.   //最后args如以下形式:  
  14.   //master { main: '/home/fjs/Desktop/pomelo/game-server/app.js' }  
  15.   
  16.   /*{ main: '/home/fjs/Desktop/pomelo/game-server/app.js', 
  17.   env: 'development', 
  18.   id: 'connector-server-1', 
  19.   host: '127.0.0.1', 
  20.   port: 4050, 
  21.   clientPort: 3050, 
  22.   frontend: 'true', 
  23.   serverType: 'connector' }*/  
  24.   
  25.   setupEnv(app, args);    //设置当前环境的配置,是开发,部署等  
  26.   loadMaster(app);    //加载master服务器的配置  
  27.   loadServers(app);   //加载server的配置  
  28.   processArgs(app, args);  
  29.   configLogger(app);  
  30. };  
代码还是很简单吧,先是获取当前的执行命令,例如:node app.js,

然后对其进行一些处理,将一些参数处理出来,这里可能要分为两种,毕竟有master服务器和非master服务器。。。他们解析出来的结果在上面的注释都已经标了出来。。。

接下来就是设置环境,例如是development或者production。。。

然后载入Master服务器的配置,然后载入普通server的配置。。。

这里我们就选一个出来看看吧,看看普通server的配置是怎么进行载入的。。。

[javascript] view plain copy print ?
  1. var loadServers = function(app) {  
  2.   app.loadConfig('servers', app.getBase() + '/config/servers.json');  //载入server类型的服务器的配置  
  3.   var servers = app.get('servers');   //获取刚刚载入的配置信息  
  4.   var serverMap = {}, slist, i, l, server;  
  5.   for(var serverType in servers) {   //遍历serve的类型,chat,gate,connector  
  6.     slist = servers[serverType];  
  7.     for(i=0, l=slist.length; i<l; i++) {    //遍历当前这种类型的server  
  8.       server = slist[i];  
  9.       server.serverType = serverType;  
  10.       serverMap[server.id] = server;   //将这些server保存到serverMap里面去  
  11.   
  12.       if(server.wsPort) {  
  13.         logger.warn('wsPort is deprecated, ' +  
  14.                     'use clientPort and frontend instead.');  
  15.       }  
  16.     }  
  17.   }  
  18.   
  19.   app.set('__serverMap__', serverMap);  //将所有的server保存到app域里去  
  20. };  
代码还是很简单的吧,首先载入配置文件,然后遍历其中server类型,然后将他们用键值对管理起来就完事了。。。

额。。

最后还有一个  processArgs(app, args);

[javascript] view plain copy print ?
  1. var processArgs = function(app, args){  
  2.   var serverType = args.serverType || 'master';   //如果没有serverType,那么就是master服务器了  
  3.   var serverId = args.id || app.getMaster().id;    //获取服务器的id  
  4.   
  5.   app.set('main', args.main, true);    //将运行信息保存起来,  
  6.     //master { main: '/home/fjs/Desktop/pomelo/game-server/app.js' }  
  7.   
  8.   /*{ main: '/home/fjs/Desktop/pomelo/game-server/app.js', 
  9.   env: 'development', 
  10.   id: 'connector-server-1', 
  11.   host: '127.0.0.1', 
  12.   port: 4050, 
  13.   clientPort: 3050, 
  14.   frontend: 'true', 
  15.   serverType: 'connector' }*/  
  16.   app.set('serverType', serverType, true);  
  17.   app.set('serverId', serverId, true);  
  18.   
  19.  if(serverType !== 'master') {  //保存当前服务器类型  
  20.     app.set('curServer', args, true);  
  21.   } else {  
  22.     app.set('curServer', app.getMaster(), true);     
  23.   }  
  24. };  
其实这个名字有点唬人,并没有执行什么命令,无非是设置了一些参数而已,。。。。。


好了,那么整个application的创建过程就差不多了,其实这部分最主要的事情还是将配置文件load进来。。。


下一篇来分析一下启动过程吧。。。。

你可能感兴趣的:(pomelo)