距离上一篇pomelo已经有一段时间了吧,总是有一些事情要做。。
这一篇来写pomelo的application的创建过程。。当然例子还是以官方的chat。。。。主要是来分析下面这段代码:
var app = pomelo.createApp();
我们首先来看看pomelo的定义吧:
var fs = require('fs'); var path = require('path'); var application = require('./application'); /** * Expose `createApplication()`. * * @module */ //这里相当于是进行命名 var Pomelo = module.exports = {}; /** * Framework version. */ Pomelo.version = '0.4'; /** * Event definitions that would be emitted by app.event */ Pomelo.events = require('./util/events'); /** * auto loaded components */ //用于保存组件 Pomelo.components = {}; /** * auto loaded filters */ //用于保存filter Pomelo.filters = {}; /** * connectors */ //connector对象 Pomelo.connectors = {}; //connector对象的get方法 Pomelo.connectors.__defineGetter__('sioconnector', function() { return require('./connectors/sioconnector'); }); //超级connector的get方法 Pomelo.connectors.__defineGetter__('hybridconnector', function() { return require('./connectors/hybridconnector'); }); /** * schedulers */ //定义调度器 Pomelo.schedulers = {}; Pomelo.schedulers.__defineGetter__('direct', function() { var m = require('./scheduler/direct'); return m; }); Pomelo.schedulers.__defineGetter__('buffer', function() { return require('./scheduler/buffer'); }); /** * global channel manager */ Pomelo.connectors.__defineGetter__('redisGlobalChannelManager', function() { return require('./common/manager/redisGlobalChannelManager'); }); //用self来指向当前的作用域 var self = this; /** * Create an pomelo application. * * @return {Application} * @memberOf Pomelo * @api public */ //创建application对象 Pomelo.createApp = function (opts) { var app = application; app.init(opts); //初始化函数 self.app = app; return app; }; /** * Get application */ //相当于是为Pomelo对象添加一个属性,app,它是一个对象,就存在一个get方法,用于返回当前的app对象 Object.defineProperty(Pomelo, 'app', { get:function () { return self.app; } }); /** * Auto-load bundled components with getters. */ //用于在components文件夹中读取组件,然后保存到components对象里面去 fs.readdirSync(__dirname + '/components').forEach(function (filename) { if (!/\.js$/.test(filename)) { return; } var name = path.basename(filename, '.js'); function load() { return require('./components/' + name); } Pomelo.components.__defineGetter__(name, load);//例如执行Pomelo.components.aa,其实会得到require("./components/aa");的值 Pomelo.__defineGetter__(name, load); }); //用于读取filter对象 fs.readdirSync(__dirname + '/filters/handler').forEach(function (filename) { if (!/\.js$/.test(filename)) { return; } var name = path.basename(filename, '.js'); function load() { return require('./filters/handler/' + name); } Pomelo.filters.__defineGetter__(name, load); Pomelo.__defineGetter__(name, load); });其实本身pomelo的定义还是很简单的,无非就是定义了一些名字,然后加载了一些组件,这里其实可以将pomelo对象看成已是一个资源的管理。。。
这里大量用到了如下的方法:
Pomelo.connectors.__defineGetter__('redisGlobalChannelManager', function() { return require('./common/manager/redisGlobalChannelManager'); });这种用法其实就是定义一下这个属性的获取方法,当Pomelo.connectors.redisGlobalChannelManager的方式访问这个属性的时候,会直接调用换进去的函数,得到返回值。。。
我们重点来分析如下代码:
//创建application对象 Pomelo.createApp = function (opts) { var app = application; app.init(opts); //初始化函数 self.app = app; return app; };由于application的定义比较长,就不一次性列出来,先来看看它的init方法。。。。
Application.init = function(opts) { opts = opts || {}; this.loaded = []; // loaded component list //用于保存所有的组件 this.components = {}; // name -> component map //调用set方法保存的参数将会保存在这个地方 this.settings = {}; // collection keep set/get this.set('base', opts.base); //事件对象 this.event = new EventEmitter(); // event object to sub/pub events // current server info this.serverId = null; // current server id this.serverType = null; // current server type this.curServer = null; // current server info // global server infos this.master = null; // master server info //用于保存所有的server,id与info的键值对 this.servers = {}; // current global server info maps, id -> info this.serverTypeMaps = {}; // current global type maps, type -> [info] this.serverTypes = []; // current global server type list appUtil.defaultConfiguration(this); //默认配置 this.state = STATE_INITED; //将当前的状态修改为已经初始化 logger.info('application inited: %j', this.getServerId()); };刚开始启动的视乎,没有参数传进来,opts就是null,代码本身也很简单吧,可以当做是对application对象的一些属性的声明和初始化。。。
这里主要是要看一下defaultConfiguration部分干了些什么。。。
我们来看看它的定义吧:
module.exports.defaultConfiguration = function (app) { var args = parseArgs(process.argv); //这里process.argv保存的是运行使用的命令,是一个数组例如[ 'node', '/home/fjs/Desktop/pomelo/game-server/app.js' ] /* [ '/usr/local/bin/node', '/home/fjs/Desktop/pomelo/game-server/app.js', 'env=development', 'id=chat-server-2', 'host=127.0.0.1', 'port=6051', 'serverType=chat' ] */ //最后args如以下形式: //master { main: '/home/fjs/Desktop/pomelo/game-server/app.js' } /*{ main: '/home/fjs/Desktop/pomelo/game-server/app.js', env: 'development', id: 'connector-server-1', host: '127.0.0.1', port: 4050, clientPort: 3050, frontend: 'true', serverType: 'connector' }*/ setupEnv(app, args); //设置当前环境的配置,是开发,部署等 loadMaster(app); //加载master服务器的配置 loadServers(app); //加载server的配置 processArgs(app, args); configLogger(app); };代码还是很简单吧,先是获取当前的执行命令,例如:node app.js,
然后对其进行一些处理,将一些参数处理出来,这里可能要分为两种,毕竟有master服务器和非master服务器。。。他们解析出来的结果在上面的注释都已经标了出来。。。
接下来就是设置环境,例如是development或者production。。。
然后载入Master服务器的配置,然后载入普通server的配置。。。
这里我们就选一个出来看看吧,看看普通server的配置是怎么进行载入的。。。
var loadServers = function(app) { app.loadConfig('servers', app.getBase() + '/config/servers.json'); //载入server类型的服务器的配置 var servers = app.get('servers'); //获取刚刚载入的配置信息 var serverMap = {}, slist, i, l, server; for(var serverType in servers) { //遍历serve的类型,chat,gate,connector slist = servers[serverType]; for(i=0, l=slist.length; i<l; i++) { //遍历当前这种类型的server server = slist[i]; server.serverType = serverType; serverMap[server.id] = server; //将这些server保存到serverMap里面去 if(server.wsPort) { logger.warn('wsPort is deprecated, ' + 'use clientPort and frontend instead.'); } } } app.set('__serverMap__', serverMap); //将所有的server保存到app域里去 };代码还是很简单的吧,首先载入配置文件,然后遍历其中server类型,然后将他们用键值对管理起来就完事了。。。
额。。
最后还有一个 processArgs(app, args);
var processArgs = function(app, args){ var serverType = args.serverType || 'master'; //如果没有serverType,那么就是master服务器了 var serverId = args.id || app.getMaster().id; //获取服务器的id app.set('main', args.main, true); //将运行信息保存起来, //master { main: '/home/fjs/Desktop/pomelo/game-server/app.js' } /*{ main: '/home/fjs/Desktop/pomelo/game-server/app.js', env: 'development', id: 'connector-server-1', host: '127.0.0.1', port: 4050, clientPort: 3050, frontend: 'true', serverType: 'connector' }*/ app.set('serverType', serverType, true); app.set('serverId', serverId, true); if(serverType !== 'master') { //保存当前服务器类型 app.set('curServer', args, true); } else { app.set('curServer', app.getMaster(), true); } };其实这个名字有点唬人,并没有执行什么命令,无非是设置了一些参数而已,。。。。。
好了,那么整个application的创建过程就差不多了,其实这部分最主要的事情还是将配置文件load进来。。。
下一篇来分析一下启动过程吧。。。。