Pomelo之application的start


这篇文章要分析如下部分的代码:
[javascript] view plain copy print ?
  1. // app configure  
  2. app.configure('production|development'function() {  
  3.     // route configures  
  4.     app.route('chat', routeUtil.chat);   //chat是server类型,第二个是route函数  
  5.   
  6.     // filter configures  
  7.     app.filter(pomelo.timeout());   //这里会同时在before和after加入这个filter   
  8. });  
  9.   
  10. // start app  
  11. app.start();  //开启application  
// app configure
app.configure('production|development', function() {
	// route configures
	app.route('chat', routeUtil.chat);   //chat是server类型,第二个是route函数

	// filter configures
	app.filter(pomelo.timeout());   //这里会同时在before和after加入这个filter 
});

// start app
app.start();  //开启application

其中最主要的其实还是分析application的start过程,先来看看configure要干一些什么东西吧:

[javascript] view plain copy print ?
  1. Application.configure = function (env, type, fn) {  
  2.   var args = [].slice.call(arguments);  //将传进来的参数变成一个数组  
  3.   fn = args.pop();   //获取回调函数  
  4.   env = 'all';     
  5.   type = 'all';  
  6.   
  7.   if(args.length > 0) {  
  8.     env = args[0];  //获取当前额环境配置,例如development,production等  
  9.   }  
  10.   if(args.length > 1) {  
  11.     type = args[1]; //类型,conector,gate啥的  
  12.   }  
  13.   
  14.   if (env === 'all' || contains(this.settings.env, env)) {   //如果没有配置env或者env包含在了配置中,  
  15.     if (type === 'all' || contains(this.settings.serverType, type)) {  
  16.       fn.call(this);  //调用回调函数  
  17.     }  
  18.   }  
  19.   return this;  
  20. };  
Application.configure = function (env, type, fn) {
  var args = [].slice.call(arguments);  //将传进来的参数变成一个数组
  fn = args.pop();   //获取回调函数
  env = 'all';   
  type = 'all';

  if(args.length > 0) {
    env = args[0];  //获取当前额环境配置,例如development,production等
  }
  if(args.length > 1) {
    type = args[1]; //类型,conector,gate啥的
  }

  if (env === 'all' || contains(this.settings.env, env)) {   //如果没有配置env或者env包含在了配置中,
    if (type === 'all' || contains(this.settings.serverType, type)) {
      fn.call(this);  //调用回调函数
    }
  }
  return this;
};

代码应该还算是很简单的吧,先将传进来的参数转化为一个数组,然后获取最后的回调函数,接着判断当前环境配置是否符合,然后再调用回调函数,进行一些设置,例如我们来看看route干了些什么:
[javascript] view plain copy print ?
  1. //设置相应server的route函数  
  2. pplication.route = function(serverType, routeFunc) {  
  3.  var routes = this.get('__routes__');  
  4.  if(!routes) {  
  5.    routes = {};  
  6.    this.set('__routes__', routes);   
  7.  }  
  8.  routes[serverType] = routeFunc;   //保存route函数  
  9.  return this;  
  10. ;  
 //设置相应server的route函数
Application.route = function(serverType, routeFunc) {
  var routes = this.get('__routes__');
  if(!routes) {
    routes = {};
    this.set('__routes__', routes); 
  }
  routes[serverType] = routeFunc;   //保存route函数
  return this;
};
这个应该是一看就能看明白这个用来干嘛了吧,第一个参数是设置route的server类型,说白了就是将这个用键值对保存起来,routefunc一般是用户自定义的route函数吧。。以后的分析肯定会涉及到。。。

然后filter用来设置filter函数,这里比较有意思的是filter分为两个维度,分别是before和after,这里会同时在这两个维度中都设置这个传进去的filter函数。。。


好了,接下来进入主题,看start函数吧:

[javascript] view plain copy print ?
  1. Application.start = function(cb) {  
  2.   if(this.state > STATE_INITED) {  //正常情况应该是等于这个  
  3.     utils.invokeCallback(cb, new Error('application has already start.'));  
  4.     return;  
  5.   }  
  6.   appUtil.loadDefaultComponents(this);  //用来加载默认的组件  
  7.   var self = this;  
  8.   //调用这些组件的start,开启这些组件  
  9.   appUtil.optComponents(this.loaded, 'start'function(err) {  
  10.     self.state = STATE_START;  
  11.     if(err) {  
  12.       utils.invokeCallback(cb, err);  
  13.     } else {  
  14.       logger.info('%j enter after start...', self.getServerId());  
  15.       self.afterStart(cb);  
  16.     }  
  17.   });  
  18. };  
Application.start = function(cb) {
  if(this.state > STATE_INITED) {  //正常情况应该是等于这个
    utils.invokeCallback(cb, new Error('application has already start.'));
    return;
  }
  appUtil.loadDefaultComponents(this);  //用来加载默认的组件
  var self = this;
  //调用这些组件的start,开启这些组件
  appUtil.optComponents(this.loaded, 'start', function(err) {
    self.state = STATE_START;
    if(err) {
      utils.invokeCallback(cb, err);
    } else {
      logger.info('%j enter after start...', self.getServerId());
      self.afterStart(cb);
    }
  });
};
其实这个函数的定义相对还是比较容易搞明白,首先判断当前的状态,如果都已经开启了,那么就报错,正常情况下应该是加载那些默认的组件,然后在开启这些组件。。。来看看loadDefaultComponents方法:
[javascript] view plain copy print ?
  1. //为application加载默认的组件  
  2. odule.exports.loadDefaultComponents = function(app) {  
  3.  var pomelo = require('../pomelo');  
  4.  // load system default components  
  5.  if (app.serverType === 'master') {  
  6.    app.load(pomelo.master, app.get('masterConfig')); //get得到的为null  
  7.    //这里pomelo.master在pomelo里面定义了,会载入components里面的master文件,这里的master其实是包装器,真正的master会在里面加载  
  8.  } else {  
  9.    app.load(pomelo.proxy, app.get('proxyConfig'));  
  10.    if(app.getCurServer().port) {  
  11.      app.load(pomelo.remote, app.get('remoteConfig'));  
  12.    }  
  13.    if(app.isFrontend()) {  
  14.      app.load(pomelo.connection, app.get('connectionConfig'));  
  15.      app.load(pomelo.connector, app.get('connectorConfig'));  
  16.      app.load(pomelo.session, app.get('sessionConfig'));  
  17.      app.load(pomelo.protobuf, app.get('protobufConfig'));  
  18.      app.load(pomelo.scheduler, app.get('schedulerConfig'));  
  19.    }  
  20.    app.load(pomelo.localSession, app.get('localSessionConfig'));  
  21.    app.load(pomelo.channel, app.get('channelConfig'));  
  22.    app.load(pomelo.server, app.get('serverConfig'));  
  23.    if(app.get('globalChannelConfig')) {  
  24.      app.load(pomelo.globalChannel, app.get('globalChannelConfig'));  
  25.    }  
  26.  }  
  27.  app.load(pomelo.monitor, app.get('monitorConfig'));  
  28. ;  
 //为application加载默认的组件
module.exports.loadDefaultComponents = function(app) {
  var pomelo = require('../pomelo');
  // load system default components
  if (app.serverType === 'master') {
    app.load(pomelo.master, app.get('masterConfig')); //get得到的为null
    //这里pomelo.master在pomelo里面定义了,会载入components里面的master文件,这里的master其实是包装器,真正的master会在里面加载
  } else {
    app.load(pomelo.proxy, app.get('proxyConfig'));
    if(app.getCurServer().port) {
      app.load(pomelo.remote, app.get('remoteConfig'));
    }
    if(app.isFrontend()) {
      app.load(pomelo.connection, app.get('connectionConfig'));
      app.load(pomelo.connector, app.get('connectorConfig'));
      app.load(pomelo.session, app.get('sessionConfig'));
      app.load(pomelo.protobuf, app.get('protobufConfig'));
      app.load(pomelo.scheduler, app.get('schedulerConfig'));
    }
    app.load(pomelo.localSession, app.get('localSessionConfig'));
    app.load(pomelo.channel, app.get('channelConfig'));
    app.load(pomelo.server, app.get('serverConfig'));
    if(app.get('globalChannelConfig')) {
      app.load(pomelo.globalChannel, app.get('globalChannelConfig'));
    }
  }
  app.load(pomelo.monitor, app.get('monitorConfig'));
};
我们还是先来看master类型吧,因为我们现在整个代码的流程还是在master类型中,还没有涉及到server类型,这里直接调用load方法将master载入进来。。。至于后面得到的配置,其实是null。

在深入load之前,需要知道pomelo.master究竟是个什么东西。。。

回顾以前的一段代码:

[javascript] view plain copy print ?
  1. //用于在components文件夹中读取组件,然后保存到components对象里面去  
  2. s.readdirSync(__dirname + '/components').forEach(function (filename) {  
  3.  if (!/\.js$/.test(filename)) {  
  4.    return;  
  5.  }  
  6.  var name = path.basename(filename, '.js');  
  7.   
  8.  function load() {  
  9.    return require('./components/' + name);  
  10.  }  
  11.  Pomelo.components.__defineGetter__(name, load);//例如执行Pomelo.components.aa,其实会得到require("./components/aa");的值  
  12.  Pomelo.__defineGetter__(name, load);  
  13. );  
 //用于在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);
});
在componets里面有了master.js文件,那么我们就知道如果访问pomelo.master,那么实际得到的是
  1. function load() {  
  2.   return require('./components/master');  
  3. }  
  function load() {
    return require('./components/master');
  }
这个函数的返回值,那么我们再来看看这个东西的定义吧:
[javascript] view plain copy print ?
  1. /** 
  2.  * Component for master. 
  3.  */  
  4. var Master = require('../master/master');  
  5.   
  6. /** 
  7.  * Component factory function 
  8.  * 
  9.  * @param  {Object} app  current application context 
  10.  * @return {Object}      component instances 
  11.  */  
  12.  //相当于require之后得到的就是这个函数  
  13. module.exports = function (app) {  
  14.   return new Component(app);  
  15. };  
  16.   
  17. /** 
  18. * Master component class 
  19. * 
  20. * @param {Object} app  current application context 
  21. */  
  22. var Component = function (app) {  
  23.   this.master = new Master(app);   //创建爱你master  
  24. };  
  25.   
  26. var pro = Component.prototype;  
  27.   
  28. /** 
  29.  * Component lifecycle function 
  30.  * 
  31.  * @param  {Function} cb 
  32.  * @return {Void} 
  33.  */  
  34. pro.start = function (cb) {  
  35.   this.master.start(cb);  
  36. };  
  37.   
  38. /** 
  39.  * Component lifecycle function 
  40.  * 
  41.  * @param  {Boolean}   force whether stop the component immediately 
  42.  * @param  {Function}  cb 
  43.  * @return {Void} 
  44.  */  
  45. pro.stop = function (force, cb) {  
  46.   this.master.stop(cb);  
  47. };  
/**
 * Component for master.
 */
var Master = require('../master/master');

/**
 * Component factory function
 *
 * @param  {Object} app  current application context
 * @return {Object}      component instances
 */
 //相当于require之后得到的就是这个函数
module.exports = function (app) {
  return new Component(app);
};

/**
* Master component class
*
* @param {Object} app  current application context
*/
var Component = function (app) {
  this.master = new Master(app);   //创建爱你master
};

var pro = Component.prototype;

/**
 * Component lifecycle function
 *
 * @param  {Function} cb
 * @return {Void}
 */
pro.start = function (cb) {
  this.master.start(cb);
};

/**
 * Component lifecycle function
 *
 * @param  {Boolean}   force whether stop the component immediately
 * @param  {Function}  cb
 * @return {Void}
 */
pro.stop = function (force, cb) {
  this.master.stop(cb);
};
(呵呵,看起来不就是一个包装器么。。。用于对真正的master进行一个代理而已。。)

从这里我们可以看到,访问pomelo.master实际上得到的是如下这个函数:

[javascript] view plain copy print ?
  1. function (app) {  
  2.   return new Component(app);  
  3. };  
function (app) {
  return new Component(app);
};

好了,搞清楚了pomelo.master是个什么东西,接下来我们就可以深入load函数了:

[javascript] view plain copy print ?
  1. //该函数用于加载组件,  
  2. pplication.load = function(name, component, opts) {  
  3.  if(typeof name !== 'string') {  
  4.    opts = component;  //工厂方法,例如start,stop等  
  5.    component = name;   //加载得到的component  
  6.    name = null;  
  7.    if(typeof component.name === 'string') {  
  8.      name = component.name;  
  9.    }  
  10.  }  
  11.   
  12.  if(typeof component === 'function') {  //如果是方法,那么就是component的构造方法,其实一般情况下就是这个样子的  
  13.    component = component(this, opts);  
  14.  }  
  15.   
  16.  if(!name && typeof component.name === 'string') {  
  17.    name = component.name;  
  18.  }  
  19.   
  20.  if(name && this.components[name]) {  
  21.    // ignore duplicat component  
  22.    logger.warn('ignore duplicate component: %j', name);  
  23.    return;  
  24.  }  
  25.   
  26.  this.loaded.push(component);    //将家在得到的component放入到数组  
  27.  if(name) {  
  28.    // components with a name would get by name throught app.components later.  
  29.    this.components[name] = component;  
  30.  }  
  31.   
  32.  return this;  
  33. ;  
 //该函数用于加载组件,
Application.load = function(name, component, opts) {
  if(typeof name !== 'string') {
    opts = component;  //工厂方法,例如start,stop等
    component = name;   //加载得到的component
    name = null;
    if(typeof component.name === 'string') {
      name = component.name;
    }
  }

  if(typeof component === 'function') {  //如果是方法,那么就是component的构造方法,其实一般情况下就是这个样子的
    component = component(this, opts);
  }

  if(!name && typeof component.name === 'string') {
    name = component.name;
  }

  if(name && this.components[name]) {
    // ignore duplicat component
    logger.warn('ignore duplicate component: %j', name);
    return;
  }

  this.loaded.push(component);    //将家在得到的component放入到数组
  if(name) {
    // components with a name would get by name throught app.components later.
    this.components[name] = component;
  }

  return this;
};
这里我们可以知道最开始传进的name是上面提到的那个函数,其余的都是null,那么这个函数的整个执行流程也就很很明白了,调用刚刚那个函数,创建一个创建一个component,其实这个component其实是对master的一个包装而已(start,stop方法),然后再将这个component放到loaded数组当中去。。这就是组件的load过程。。。。(当然这里只是master的load过程)


好了,master组件load进来了,那么就应该启动了,也即是执行如下的代码:

[javascript] view plain copy print ?
  1. //调用这些组件的start,开启这些组件  
  2. appUtil.optComponents(this.loaded, 'start'function(err) {  
  3.   self.state = STATE_START;  
  4.   if(err) {  
  5.     utils.invokeCallback(cb, err);  
  6.   } else {  
  7.     logger.info('%j enter after start...', self.getServerId());  
  8.     self.afterStart(cb);  
  9.   }  
  10. });  
  //调用这些组件的start,开启这些组件
  appUtil.optComponents(this.loaded, 'start', function(err) {
    self.state = STATE_START;
    if(err) {
      utils.invokeCallback(cb, err);
    } else {
      logger.info('%j enter after start...', self.getServerId());
      self.afterStart(cb);
    }
  });
好吧,我们来看这个函数的定义:
[javascript] view plain copy print ?
  1. module.exports.optComponents = function(comps, method, cb) {  
  2.   var i = 0;  
  3.   //遍历所有的组件,调用他们相应的方法  
  4.   async.forEachSeries(comps, function(comp, done) {  
  5.     i++;  
  6.     if(typeof comp[method] === 'function') {  
  7.       comp[method](done);  
  8.     } else {  
  9.       done();  
  10.     }  
  11.   }, function(err) {  
  12.     if(err) {  
  13.       logger.error('fail to operate component, method:%s, err:' + err.stack, method);  
  14.     }  
  15.     cb(err);  
  16.   });  
module.exports.optComponents = function(comps, method, cb) {
  var i = 0;
  //遍历所有的组件,调用他们相应的方法
  async.forEachSeries(comps, function(comp, done) {
    i++;
    if(typeof comp[method] === 'function') {
      comp[method](done);
    } else {
      done();
    }
  }, function(err) {
    if(err) {
      logger.error('fail to operate component, method:%s, err:' + err.stack, method);
    }
    cb(err);
  });
比较的简单,对于这里我们载入的master组件,说白了就是调用它的start函数,
[javascript] view plain copy print ?
  1. pro.start = function (cb) {  
  2.   this.master.start(cb);  
  3. };  
pro.start = function (cb) {
  this.master.start(cb);
};
只不过是一个包装而已,用于调用真正的master的start函数。。。


好了,到这里master组件的载入和start也就差不多了,那么下一篇就可以看看master的start究竟是干了些什么事情了。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值