jxTMS:低成本快速定制的业务系统个人开发平台。
服务
作为一个面向业务管理系统快速定制开发平台的jxTMS,笔者一直以来都比较排斥目前非常流行的微服务概念,毕竟对于业务管理系统来说,稳定、可靠是第一位的,所以笔者一直避免服务化的运用。
但在用jxTMS来开发一个少儿编程大赛时,由于需要将python和c++的源码编译后运行,所以不得不启用了服务的概念来实现。由此笔者也对服务有了更深刻的认识,由于jxTMS在设计之初,不停机的动态升级能力【即热机刷新】就是其必须要实现的核心能力之一,而之前在讨论python时我也说过,jxTMS通过叠加模式对python只用到了非常少的一部分,所以capa的能力是针对业务管理进行优化的,业务管理之外的很多能力就是不够的。那么,服务化就意味着可进一步的实现重大能力的动态扩展与升级。
注1:轻用户编程是jxTMS的另一核心能力,因为这意味着降低开发者的要求,这是降低开发成本的必要条件。所以服务化就是轻用户编程是和动态升级在扩展重大能力方面的一个非常好的解决方案
注2:利用java动态导入jar包的方式也能解决,但考虑到业务管理系统对稳定性、可靠性的要求,自然不希望对基础平台有任何变动,所以直接排除了该方案
在权衡利弊之后,jxTMS基于消息队列实现了服务化的能力。
jxTMS中的服务是基于workQueue来实现的,所以一个服务可以有多个服务点同时提供服务,由MQ【jxTMS目前支持rabbitMQ】轮转分发服务请求。所以提供服务者应具备冥等能力,即无状态、一次性服务完毕后归零,如果无法做到冥等,则只能提供单点服务,就没有了服务天生的热备能力。
jxTMS中的服务提供了一个消息广播频道,服务可通过该频道对感兴趣者提供广播,而监听这个频道没有任何要求。
jxTMS中的服务有两种访问方法:inform和request,两者的区别在于:
-
inform不等待服务点返回响应,在投递消息后即结束,可视为事件通知
-
request则需要等待服务点返回响应,没有响应则一直阻塞直到超时【目前设置为30秒,可配置】,这是主要的服务访问方式
注:inform的使用需注意服务的冥等要求。也就是说,如果要求冥等,则inform的事件要么保存到数据库中【但这样效率较低、或需要启用缓存功能】,要么另起一个服务间的广播频道进行同步
jxTMS基于java平台提供了基础的service类,只需继承该类即自动启动了一个服务,然后为其增加服务响应函数即可,如:
//java代码
public class catalogService extends service {
public catalogService() throws Exception {
super(serviceName_catalogService);
//注册
setServer("register", (sender, json) -> {
try {
//客户发送的register请求会在这样进行处理
//根据json中的信息完成客户端注册
return jxJson.msgJson("ok");
} catch (Exception e) {
jxLog.error(e);
return jxJson.errJson(e.getMessage());
}
});
}
}
上述代码即声明了一个目录服务,然后为其添加了一个register请求的响应函数。然后客户端通过调用request函数即可请求相应的服务:
//go代码
func getData(name string) *json.Json {
rs := json.New()
rs.Set("name",name)
ts := time.Now().Format("2006-01-02 15:04:05")
rs.Set("t",ts)
id++
rs.Set("id",id)
return rs
}
func main() {
//注册一个消息接收点r1,否则无法发送消息
msg.Listen("r1",nil)
//通过r1向testPyService发送一个register请求,参数来自getData函数的返回值,json格式
rs := service.Request("r1","testPyService","register",getData("ttt111"))
PrintInfo(rs)
}
上述代码演示的是在go中向testPyService服务注册ttt111。而testPyService是由python通过go实现的服务接口启动的:
#python代码
def getMsg(ty,n):
ps={}
ps['type']=ty
ps['name']=n
return ps
def cmd111(ps):
print(ps)
#在响应过程中,广播一个事件给所有感兴趣者
s.boradcastEvent("event111",getMsg('event','event111'))
return getMsg('respond','cmd111')
#启动testPyService服务
s = jxGoService("testPyService")
#注册register请求的响应函数
s.addCmdDual("register",cmd111)
请注意:testPyService服务在接受到register请求的响应处理中,还利用boradcastEvent广播了一个event111事件。
注:testPyService只是用于测试,未在python端进一步封装,所以其声明为一个全局变量s,然后在响应函数中直接引用了该全局变量
这样,testPyService服务可通过启动脚本随服务器一同启动【或其它独立于jxTMS的服务管理策略】,而开发者只需要在capa.py中用服务类的Request函数对该服务进行请求即可。
目前,jxTMS已经打包为云服务器镜像,开发者开箱即用:
jxTMS-腾讯云市场