代码改变世界

服务化配置的另一种可能

2017-11-13 16:05  春哥大魔王  阅读(947)  评论(0编辑  收藏  举报

项目背景

项目是给内部团队用的,也算是业务场景较为复杂的系统,这种系统较于互联网C端产品,用户量不大,QPS峰值不会太高,但业务会比较复杂,业务变动比较频繁。

其中一个校验的功能点会对客户端文件内容进行规则性的判断和校验,不同校验结果吐出不同的国际化信息。

最开始的考量是业务校验属于非核心业务内容,不应该和具体业务有较强的依赖,属于可拔插配置,可随时替换。

实现方式

基于可拔插,可配置,变化频繁的特点考虑,希望通过服务化配置的方式对这部分规则进行注入。

服务化场景下,配置分为:静态配置和动态配置。

静态配置主要是环境变量相关,一般在项目第一次启动时进行依赖与使用,后期基本不变,修改之后需要重新发布项目。

动态配置属于系统运行期间可动态进行修改,不同配置参数下,系统有不同的行为表现,常见的有数据库,redis配置信息,多线程数量等,多以key-value形式配置,规则较为单一。

由于校验规则特点,决定引入一个可应对复杂业务场景下的动态配置方式,最后选定了JPython。

几年前刚毕业的时候做电商的边栏你可能感兴趣的产品,当时没有深度学习和推荐引擎的概念,通过人工方式在商品管理平台对商品打TAG,之后通过聚合TAG信息将同TAG产品绑定在感兴趣的栏位上,由于需要实时生效,变化也比较频繁,就采用了这种静态语言+动态脚本的方式实现了那个功能。

这次的实现方式依旧,通过Py脚本进行规则编写,第一次将Py脚本装载入JVM之后,后面对Py脚本的修改可实时生效。

需要引入的依赖:

<dependency>  
<groupId>org.python</groupId>  
<artifactId>jython-standalone</artifactId>  
<version>2.7.0</version>  
</dependency> 

通过自定义注解方式,实现对指定请求进行规则配置,在拦截器上拦截请求及注解配置参数,路由到不同的Py校验脚本上,传入参数,校验结果以脚本方式返回,映射到不同的Java枚举上。

验证拦截器与Py互动代码:

String pyFile = "CTD03Validator.py"; 注解配置
pyFile = "...\\validate\\ct\\" + pyFile;
InputStream inputStream = new FileInputStream(pyFile);
PythonInterpreter interpreter = new PythonInterpreter();
interpreter.execfile(pyFile);
inputStream.close();
// 第一个参数为期望获得的函数(变量)的名称,第二个参数为期望返回的对象类型
String json = GsonUtil.GsonString(data);
String funcName = "validate";
PyFunction function = interpreter.get(funcName, PyFunction.class);
PyObject object = function.__call__(new PyString(json));// 函数调用
logger.info("Py验证器执行结果,object: {}", object);
return ErrorType.getErrorType(object.toString());

Py核心校验代码:

# -*- coding: UTF-8 -*-
import os.path
import json
# 校验入口
def validate(jsonData):
obj = json.loads(jsonData)
content = obj['content']
# 校验标题
result = checkRadioTopic(content)
if ('' != result and 'success' != result):
return result
print '校验标题~'
# 校验选项
result = checkRadioOption(content)
if('' != result and 'success' != result):
return result
print '校验选项~'
print '完成校验~'
return result

最终实现动态规则的修改及及时生效,由于Py中主要时CPU运算场景不涉及IO操作,同时是内部项目,故性能问题不会产生影响。