【Pomelo源码分析】2016-09-21 程序入口(app.js, pomelo.js, application.js)

来源:互联网 发布:消耗臭氧层物质 知乎 编辑:程序博客网 时间:2024/06/04 19:23

程序入口


通过入门一章可以看到,pomelo start启动时其实是运行node app.js,程序入口也即app.js文件。

app.js


  • 引入pomelo库
  • 调用pomelo的createApp生成app对象。
  • 设置app名称为当前项目名称,默认为文件夹名。
  • 设置app的connector,类型为pomelo init时选择的类型,具体参数之后详解,主要包含传输层协议、心跳是否开启、心跳超时时间、心跳间隔时间、超时关闭时间等。
  • 启动app.start。
  • 设置当前程序中未被捕捕捉而浮到顶层的异常处理。

pomelo.js


模块依赖

  • fs:文件操作库,node默认模块
  • path:路径操作库,node默认模块
  • application:pomelo的应用的主体模块,之后需重点分析
  • package:包信息,json文件
    其中package为纯json文件,导入后为json对象,仅使用了其version字段初始化Pomelo对象的version。故仅有application对象为导入的自定义模块。

初始化

  • 使用package.version初始化version属性
  • 使用./util/events做为events,定义应用可接收的事件列表
  • 初始化空白的components、filters、rpcFilters
  • 初始化connectors和pushSchedulers。这部分采用了动态加载的方式,使用__defineGetter__ + load.bind实现,__defineGetter__使对象对于获取某属性时调用某方法,而load函数为require模块的具体函数,通过bind(null, path)可以消除函数调用时的this上下文,获得一个全局的静态函数,避免对外部Pomelo对象的误操作。其中connector包含sioconnector、hybridconnector、udpconnector、mqttconnector等四种,pushScheduler包含direct、buffer两种。
  • createApp函数:创建应用的方法,调用application的init方法来初始化应用,并将其赋给Pomelo.app,并返回app。
  • 设置Pomelo对象的app属性的getter,返回Pomelo的app,不确定此设定的作用是什么。
  • 初始化其他所有组件
    • 初始化components:读取./components文件夹下的文件,若不是js文件则退出。获取文件名并使用__defineGetter + load.bind实现动态加载,每个文件会被绑定到Pomelo.components对象和Pomelo根对象下。
    • 初始化filter/handler:方式同components,同样绑定到Pomelo.filters和Pomelo根对象下。
    • 初始化filter/rpc:方式同components,仅绑定到Pomelo.rpcFilters对象下。

总结

较为简单的入口,大头在application中,而这边仅负责了一些模块的动态加载绑定。需要注意的是components和filter/handler都会注册Pomelo根对象下的getter,所以文件名不要出现重复,且尽量使用完整路径,由于是动态加载,则使用完整路径访问时即使重名也不会出现冲突。

util/events.js


定义了应用可处理事件的字符串常量对象。

application.js


应用主体文件,代码上千行,是应用主要管理部分。

模块依赖

  • ./util/utils:工具类,包含一些实用工具函数,之后介绍。
  • pomelo-logger:非常好用的pomelo-logger日志处理类,用于处理当前文件的日志输出。
  • events.EventEmitter:使用Node官方的Events模块来处理事件监听和通知。
  • ./util/events:应用可处理事件的字符串常量对象。
  • ./util/appUtil:面向应用的工具类,之后介绍。
  • ./util/constants:常量对象。
  • ./common/manager/appManager:应用管理类,之后介绍。
  • fs & path:Node官方提供的文件处理和路径处理库。

  • 设置应用的生命周期状态常量:1-已初始化(STATE_INITED),2-应用启动中(STATE_START),3-应用已启动(STATE_STARTED),4-应用已停止(STATE_STOPED)

Application.init

  • 应用初始化函数
  • 声明一些成员变量,通过初始化为空数组或对象确定该变量的类型,然后调用appUtil.defaultConfiguration函数进行配置写入,修改状态为1,输出已初始化的日志信息。

Application.configureLogger

  • 配置Logger,配置文件为{$base}/config/log4js.json,也会寻找带有env的目录下的配置文件

Application.filter

  • 设置过滤器,即预处理和后处理函数,该函数接收的过滤器参数应含有before和after两个方法成员

Application.before

  • 设置预处理过滤器,其参数列表为(msg, session, next)

Application.after

  • 设置后处理过滤器,其参数列表为(err, msg, session, resp, next)

Application.globalFilter

  • 设置全局过滤器,同filter

Application.globalBefore & Application.globalAfter

  • 设置全局预处理和后处理函数,同before & after

Application.rpcFilter

  • 设置RPC过滤器,该过滤器应包含有before和after两个方法成员

Application.rpcBefore

  • 设置RPC调用的预处理函数,其参数列表为(serverId, msg, opts, next)

Application.rpcAfter

  • 设置RPC调用的后处理函数,其参数列表为(serverId, msg, opts, next)

Application.load

  • 加载组件函数,接受的参数为name:组件名称,component:组件实例或工厂函数,opts:用于传递给工厂函数的参数
  • 若不存在name,则一次重新调整component和opts,并尝试从component获取name
  • 若component为函数,则调用该函数,传入application与opts进行构造
  • 若此时components中已包含有同名组件,则警告并返回
  • 向loaded中添加该组件
  • 在components中以组件名为键名,组件实例为键值存储,以便之后取用
  • 返回application自身以用于链式调用

Application.loadConfigBaseApp(还有一个loadConfig函数,应为旧版不支持env的)

  • 从json文件加载配置,接受参数为key,value,reload:是否在文件变化后重新加载
  • 形成两个配置路径,并逐一搜索,若找到则直接set到application中
  • 若路径存在,且reload为true,则使用fs.watch监控文件,对change事件做重新加载操作(需要先delete require.cache,否则依然会加载到相同的内容)

Application.route

  • 配置路由,接受参数为serverType:服务器类型,routeFunc:路由函数,路由函数的参数列表为(session, msg, app, cb)
  • 首先获取application的routes,若不存在则创建空对象并赋回application中
  • 将当前的routeFunc赋给特定类型的server
  • 返回application自身以用于链式调用

Application.beforeStopHook

  • 服务器停止前调用的函数,已在0.8之后的版本中弃用

Application.start

  • 项目启动函数*
  • 检查当前项目状态,若已经超过初始化状态,则项目已经启动,则向回调函数传入错误信息并返回
  • 启动当前application,若不为master服务器,则直接runServer。若为master,则查看lifecycleCbs中是否存在beforestartup函数,若存在则先调用,并传入启动函数,否则直接调用启动函数。启动函数的内容为:传入loaded组件数组,以及start函数名,若这些组件中存在start函数,则调用该函数。组件start调用完毕后设置当前application状态为STATE_START并调用afterStart方法。

Application.afterStart

  • 启动后处理函数
  • 检查服务器当前状态,若不为STATE_START则向回调函数传入错误信息并返回
  • 获取lifecycleCbs中的afterstartup函数
  • 尝试调用loaded所有组件的afterstart函数
  • 若afterstartup函数存在,则调用该函数
  • 输出启动时间,并emitSTART_SERVER事件

Application.stop

  • 停止应用的函数
  • 若当前状态大于STATE_STARTED,则报错退出
  • 设置状态为STATE_STOPED
  • 设置一个3s的计时器,若应用未能在3s内成功关闭,则强制退出
  • 查看lifecycle中的beforeshutdown函数,若存在则调用。否则查看beforestophook,若存在则调用。
  • 调用appUtil的stopComps方法,组件停止后清空超时计时器,正常退出。若为强制退出,则理解退出。

Application.set

  • 向application添加某设置
  • 将key-value对设置到application的settings对象中
  • 若attach为真,则直接将该key设置到application的根对象中

Application.get

  • 获取某设置

Application.enabled & Application.disabled

  • 检查某设置是否被使用,使用!和!!实现

Application.enable & Application.disable

  • 通过设置为true或false开启或关闭某个应用设置项

Application.configure

  • 对于特定的env和服务器type进行设置
  • 默认为所有env和type进行设置
  • 若当前env和type符合要求,则调用configure回调函数,该函数对application中的设置进行覆盖修改

Application.registerAdmin

  • 注册admin模块,该模块是监控系统的扩展点
  • 获得application的modules属性,若为空,则创建新的对象
  • 根据传入的参数列表初始化该module并放入modules对象中
  • 为何称为Admin?感觉像是一个module存储方法

Application.use

  • 使用plugin插件方法
  • 传入的plugin应包含components属性,否则报错返回
  • 尝试读取plugin.components文件,并将组件load到application中
  • 若plugin中包含events,则尝试读取文件,并将events中的事件bind到application的event监听上。
  • 这部分可实现组件和事件的高扩展能力,可以直接通过plugin方式向application内添加组件和事件,而plugin本身可以完全在独立的文件夹下。

Application.transaction

  • 应用的事务处理函数,直接调用了appManager的transaction函数

Application.getMaster

  • 获取应用master服务器的信息,获得的信息内容为{id, host, port}

Application.getCurServer

  • 获取当前服务器的信息,获得的信息内容为{id, serverType, host, port}

Application.getServerId

  • 获取当前服务器的服务器ID

Application.getServerType

  • 获取当前服务器的类型

Application.getServers

  • 获取当前应用所有服务器的信息,返回的信息为id-info的键值对

Application.getServerById

  • 根据Server ID获取一个服务器在当前集群中的信息

Application.getServerFromConfig

  • 根据Server ID从配置文件中获取某服务器的配置信息

Application.isFrontend

  • 检查某服务器是否为前端服务器

Application.isBackend

  • 检查某服务器是否为后端服务器

Application.isMaster

  • 检查当前服务器是否为master服务器

Application.addServers

  • 运行时热添加新服务器的函数
  • 更新servers属性
  • 更新serverTypeMaps属性,使用replaceServer
  • 更新serverType属性
  • 发送ADD_SERVERS事件

Application.removeServers

  • 运行时根据id热删除服务器的函数
  • 更新servers属性、serverTypeMaps属性
  • 发送REMOVE_SERVERS事件

Application.replaceServers

  • 运行时热替换服务器信息
  • 清空servers、serverTypeMaps、serverTypes属性,并根据传入的servers信息重新初始化这些属性
  • 发送REPLACE_SERVERS事件

Application.addCons & Application.removeCrons

  • 运行时热添加或热删除con定时脚本
  • 直接将参数发送到ADD_CRONS和REMOVE_CRONS事件上,由事件处理器进行处理

部分工具函数,不介绍

总结

application是pomelo启动时真正启动的类,其中包含了最顶层的一些处理方法,但一些核心方法,如启动服务器、事务处理等则由appUtil和appManager等类进行,如进一步的阅读需要从这些核心类开始。

0 0
原创粉丝点击