该文章是基于上一篇文章的项目(pomelo解耦代码组织)
热更新的目的在于不用重启服务器就能更新服务端代码,其中一个场景是:
暴露给服务端的接口,不需要更新,接口包装了具体的服务,这个服务是可以热更新的。即实现了暴露给客户端的接口和实现分离,又能达到热更新的目的。
需求:暴露给客户端的 handler 和具体的实现分离,并且具体的实现能用bearcat热更新。
GoodsService.js 是服务端逻辑代码,可能会热更新
gameHandler.js 是客户端接口 ,不用更新,拥有一个具体的逻辑服务对象的引用,该引用是bearcat维护
因为要热更新,需要热更新的变量 的定义有几个约定,下面会列出。
准备,安装npm install bearcat
1.根目录下新建文件contex.json(bearcat配置文件)
//默认就行
{
"name": "GameSrv",
"scan": "app",
"beans": []
}
- //默认就行
- {
- "name": "GameSrv",
- "scan": "app",
- "beans": []
- }
//默认就行
{
"name": "GameSrv",
"scan": "app",
"beans": []
}
2.修改app.js代码
var bearcat = require("bearcat");
bearcat.createApp([require.resolve('./context.json')], { // 刚新建的配置文件
BEARCAT_LOGGER: 'off',
BEARCAT_HOT: 'on',// 开启热更新,如果是off 那么不会热更新
BEARCAT_FUNCTION_STRING: true
});
bearcat.start(function () {
Config();
// start app
app.start();
});
- var bearcat = require("bearcat");
- bearcat.createApp([require.resolve('./context.json')], { // 刚新建的配置文件
- BEARCAT_LOGGER: 'off',
- BEARCAT_HOT: 'on',// 开启热更新,如果是off 那么不会热更新
- BEARCAT_FUNCTION_STRING: true
- });
- bearcat.start(function () {
- Config();
- // start app
- app.start();
- });
var bearcat = require("bearcat");
bearcat.createApp([require.resolve('./context.json')], { // 刚新建的配置文件
BEARCAT_LOGGER: 'off',
BEARCAT_HOT: 'on',// 开启热更新,如果是off 那么不会热更新
BEARCAT_FUNCTION_STRING: true
});
bearcat.start(function () {
Config();
// start app
app.start();
});
3.修改gameHandler.js,其中有一些约定,结构
var bearcat = require("bearcat");
var Handler = function (app) {
this.$id = "Handler"; //约定 ,this.$id= 代表该模块名字,该字段经测试 可去掉,但是官网demo 有该字段
this.$GoodsService = null; // 约定this.$需要更新的模块名字=null bearcat就会把null标记的进行热更新
}
var handler = Handler.prototype;
handler.getNotify = function (msg, session, next) {
if (!session.uid) {
next(null, { msg: "玩家未登录!" });
return;
}
next(null, { msg: "欢迎玩家" + msg.name + "进入游戏" });
};
handler.buyGoods = function (msg, session, next) {
this.$GoodsService.buyGoods(msg.id, session.uid, next);
}
//导出约定:函数式返回 return bearcat.getBean(Handler); /Handler为该模块名字,也就是定义的function名字
module.exports = function (app) {
return bearcat.getBean(Handler);// 此时getBean函数会给this$XXX=null的对象赋值
};
- var bearcat = require("bearcat");
- var Handler = function (app) {
-
- this.$id = "Handler"; //约定 ,this.$id= 代表该模块名字,该字段经测试 可去掉,但是官网demo 有该字段
- this.$GoodsService = null; // 约定this.$需要更新的模块名字=null bearcat就会把null标记的进行热更新
- }
- var handler = Handler.prototype;
- handler.getNotify = function (msg, session, next) {
-
- if (!session.uid) {
- next(null, { msg: "玩家未登录!" });
-
- return;
- }
-
- next(null, { msg: "欢迎玩家" + msg.name + "进入游戏" });
-
- };
- handler.buyGoods = function (msg, session, next) {
-
- this.$GoodsService.buyGoods(msg.id, session.uid, next);
- }
- //导出约定:函数式返回 return bearcat.getBean(Handler); /Handler为该模块名字,也就是定义的function名字
- module.exports = function (app) {
- return bearcat.getBean(Handler);// 此时getBean函数会给this$XXX=null的对象赋值
- };
var bearcat = require("bearcat");
var Handler = function (app) {
this.$id = "Handler"; //约定 ,this.$id= 代表该模块名字,该字段经测试 可去掉,但是官网demo 有该字段
this.$GoodsService = null; // 约定this.$需要更新的模块名字=null bearcat就会把null标记的进行热更新
}
var handler = Handler.prototype;
handler.getNotify = function (msg, session, next) {
if (!session.uid) {
next(null, { msg: "玩家未登录!" });
return;
}
next(null, { msg: "欢迎玩家" + msg.name + "进入游戏" });
};
handler.buyGoods = function (msg, session, next) {
this.$GoodsService.buyGoods(msg.id, session.uid, next);
}
//导出约定:函数式返回 return bearcat.getBean(Handler); /Handler为该模块名字,也就是定义的function名字
module.exports = function (app) {
return bearcat.getBean(Handler);// 此时getBean函数会给this$XXX=null的对象赋值
};
4.修改GoodsService.js //
//该模块可能会热更新,和普通的js模块结构没什么区别,注意 导出不要new 直接导出模块名字即可
function GoodsService() {
// this.$id = "GoodsService";
console.error("[GoodsService]:new GoodsService");
}
GoodsService.prototype.buyGoods = function (id, owner, next) {
if (!owner) {
next(null, { msg: "玩家未登录!" });
return;
}
///////////////////////////////
if (true) {//验证购买条件 允许购买
//修改数据库
var sql = " insert into `goods` (`id`, `owner`) VALUES(?, ?)";
var args = [id, owner];
var dbclient = pomelo.app.get('dbclient');//获取全局mysql client
console.log(dbclient);
dbclient.query(sql, args, function (err, res) {//执行sql语句 函数insert和query等效
if (err) { // 购买失败
console.error("[Error]:数据库服务器错误");
next(null, { msg: "购买失败,服务器错误!", code: 200 });
}
else {//购买成功
next(null, { msg: "购买物品:#活血丹 成功", code: 200 });
}
});
} else { // 不允许购买
next(null, { msg: "你的金币不足,购买失败", code: 200 });
}
};
module.exports = GoodsService;
- //该模块可能会热更新,和普通的js模块结构没什么区别,注意 导出不要new 直接导出模块名字即可
- function GoodsService() {
- // this.$id = "GoodsService";
-
- console.error("[GoodsService]:new GoodsService");
- }
- GoodsService.prototype.buyGoods = function (id, owner, next) {
-
- if (!owner) {
- next(null, { msg: "玩家未登录!" });
- return;
- }
- ///////////////////////////////
-
- if (true) {//验证购买条件 允许购买
-
- //修改数据库
-
-
- var sql = " insert into `goods` (`id`, `owner`) VALUES(?, ?)";
-
- var args = [id, owner];
- var dbclient = pomelo.app.get('dbclient');//获取全局mysql client
-
- console.log(dbclient);
- dbclient.query(sql, args, function (err, res) {//执行sql语句 函数insert和query等效
- if (err) { // 购买失败
- console.error("[Error]:数据库服务器错误");
- next(null, { msg: "购买失败,服务器错误!", code: 200 });
- }
- else {//购买成功
- next(null, { msg: "购买物品:#活血丹 成功", code: 200 });
- }
- });
- } else { // 不允许购买
- next(null, { msg: "你的金币不足,购买失败", code: 200 });
- }
- };
- module.exports = GoodsService;
//该模块可能会热更新,和普通的js模块结构没什么区别,注意 导出不要new 直接导出模块名字即可
function GoodsService() {
// this.$id = "GoodsService";
console.error("[GoodsService]:new GoodsService");
}
GoodsService.prototype.buyGoods = function (id, owner, next) {
if (!owner) {
next(null, { msg: "玩家未登录!" });
return;
}
///////////////////////////////
if (true) {//验证购买条件 允许购买
//修改数据库
var sql = " insert into `goods` (`id`, `owner`) VALUES(?, ?)";
var args = [id, owner];
var dbclient = pomelo.app.get('dbclient');//获取全局mysql client
console.log(dbclient);
dbclient.query(sql, args, function (err, res) {//执行sql语句 函数insert和query等效
if (err) { // 购买失败
console.error("[Error]:数据库服务器错误");
next(null, { msg: "购买失败,服务器错误!", code: 200 });
}
else {//购买成功
next(null, { msg: "购买物品:#活血丹 成功", code: 200 });
}
});
} else { // 不允许购买
next(null, { msg: "你的金币不足,购买失败", code: 200 });
}
};
module.exports = GoodsService;
5.启动服务器:运行结果正常,
测试热更新:修改逻辑代码 GoodsService.js
console.log(" .............. new Version . .......");
- console.log(" .............. new Version . .......");
console.log(" .............. new Version . .......");
修改后保存,可以看到服务端日志输出
热更新成功