Pomelo之application的start

来源:互联网 发布:部落冲突升级数据 编辑:程序博客网 时间:2024/05/16 07:54
这篇文章要分析如下部分的代码:
// app configureapp.configure('production|development', function() {// route configuresapp.route('chat', routeUtil.chat);   //chat是server类型,第二个是route函数// filter configuresapp.filter(pomelo.timeout());   //这里会同时在before和after加入这个filter });// start appapp.start();  //开启application

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

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干了些什么:
 //设置相应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函数吧:

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方法:
 //为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究竟是个什么东西。。。

回顾以前的一段代码:

 //用于在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,那么实际得到的是
  function load() {    return require('./components/master');  }
这个函数的返回值,那么我们再来看看这个东西的定义吧:
/** * 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实际上得到的是如下这个函数:

function (app) {  return new Component(app);};

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

 //该函数用于加载组件,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进来了,那么就应该启动了,也即是执行如下的代码:

  //调用这些组件的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);    }  });
好吧,我们来看这个函数的定义:
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函数,
pro.start = function (cb) {  this.master.start(cb);};
只不过是一个包装而已,用于调用真正的master的start函数。。。


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

原创粉丝点击