【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
- 【Pomelo源码分析】2016-09-21 程序入口(app.js, pomelo.js, application.js)
- 【Pomelo源码分析】2016-09-20 入门(pomelo命令)
- pomelo源码分析(5)--node.js中的this
- Node.js pomelo 教程
- pomelo js 经典函数
- pomelo源码分析(二)
- pomelo源码分析(三)
- pomelo源码分析(四)
- pomelo源码分析(五)
- pomelo源码分析(六)
- pomelo+cocos2d-js之初学笔记一
- 【POMELO】深入浅出node.js游戏服务器开发
- ubuntu下安装node.js、pomelo
- 在cocos2d-js中使用pomelo
- cocos2d-js + pomelo 的开发环境搭建
- pomelo源码分析(一)
- Pomelo聊天室源码分析(一)
- (pomelo系列入门教程)深入浅出node.js游戏服务器开发——基于Pomelo的MMO RPG开发
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
- hive视图操作
- JavaScript学习之旅-导言篇
- 苹果电脑如何去除select的圆角
- A child container failed during start
- 【Pomelo源码分析】2016-09-21 程序入口(app.js, pomelo.js, application.js)
- Wampserver2.5连接SqlServer2014数据库配置步骤
- HDU 5898 odd-even number(数位dp)
- 性能优化CPU、内存、磁盘I/O、网络性能相关命令
- 最简单的openshift免费空间上传代码教程!和FTP一样简单!
- Appdelegate的代理方法简单解析
- bzoj 1935: [Shoi2007]Tree 园丁的烦恼
- Permutations II
- Linux链接命令