- 简要介绍
在工程中,我们采用protobuf V3和SpringBoot搭建服务化体系,我们需要一个基于protobuf协议的辅助工具提升效率。我们提供服务级别和方法级别的文档注解,在工程编译期间产生文档数据,利用这些文档数据生成在线文档和接口测试界面,同时提供在线协议编辑器,编译工具,打包和上传SDK到repository等,同时将中台自动化测试用例挂在daily loadbuild的task中,每天定时执行。中台能力建设的核心是围绕Protobuf协议的两个注解,下面会做介绍。
- 注解实现代码
GitHub - gilbertwang1981/idl-doc-generator: 基于protobuf V3协议的一套注解,能够辅助实现在线文档以及在线测试界面
- 使用实例如下:
引入依赖包;
compile('com.hs:idl-doc-generator:0.0.4')
在SpringBoot的接口文件中使用文档类注解和方法注解;
@DocService(module = "分布式计划任务调度中心管理接口", service = "dschedule-service", value = "/dsch")
public interface DSchServiceInterface {
@DocMethod(desc = "【任务端】调度器节点注册", method = { DocRequestMethod.POST }, name = "/registerNode",
produces = { "application/x-protobuf" },
parameterType = DSchRegisterNodeRequest.class , parameterTypeIdl = "DSchAdminProto.proto",
returnType = DSchRegisterNodeResponse.class, returnTypeIdl = "DSchAdminProto.proto")
public DSchRegisterNodeResponse registerNode(DSchRegisterNodeRequest request);
}
设置环境变量;
# 文档数据将被保存在/root/test/dschedule-service文件中
export DOC_GEN_PATH="/root/test"
export DOC_GEN_PROJECT="dschedule-service"
编译工程,生成文档数据,json格式;
{
"project": "doc-gen",
"services": [{
"service": "dschedule-service",
"module": "分布式计划任务调度中心管理接口",
"value": "/dsch",
"version": "1.0",
"methods": [{
"name": "/registerNode",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【任务端】调度器节点注册",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchRegisterNodeRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchRegisterNodeResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"host": "java.lang.Object",
"serviceName": "java.lang.Object",
"desc": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int",
"nodeId": "java.lang.Object"
}
}, {
"name": "/registerJob",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【任务端】调度器节点任务注册",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchRegisterJobRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchRegisterJobResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"jobName": "java.lang.Object",
"strategy": {
"cron": "java.lang.Object",
"fixedDelay": "long",
"fixedRate": "long",
"initialDelay": "long"
},
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"jobId": "java.lang.Object",
"resCode": "int",
"nodeId": "java.lang.Object"
}
}, {
"name": "/getJobStatus",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【管理端】获取任务状态",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchJobStatusRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchJobStatusResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"jobId": "java.lang.Object",
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int",
"job": {
"jobId": "java.lang.Object",
"beginTime": "long",
"endTime": "long"
}
}
}, {
"name": "/getNodeStatus",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【管理端】获取节点状态",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchNodeStatusRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchNodeStatusResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"node": {
"activeThreads": "long",
"mem": "long",
"cpu": "long",
"updateTime": "long",
"nodeId": "java.lang.Object"
},
"resCode": "int"
}
}, {
"name": "/jobHealthCheck",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【任务端】任务健康检查",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchJobHealthCheckRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchJobHealthCheckResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"job": {
"jobId": "java.lang.Object",
"beginTime": "long",
"endTime": "long"
},
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int"
}
}, {
"name": "/nodeHealthCheck",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【任务端】节点健康检查",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchNodeHealthCheckRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchNodeHealthCheckResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"node": {
"activeThreads": "long",
"mem": "long",
"cpu": "long",
"updateTime": "long",
"nodeId": "java.lang.Object"
},
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int"
}
}, {
"name": "/getCommand",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【任务端】获取调度器任务命令",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchCommandRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchCommandResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"jobId": "java.lang.Object",
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"nodeId": "java.lang.Object",
"command": {
"jobId": "java.lang.Object",
"cmdType": "int"
}
}
}, {
"name": "/addCommands",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【管理端】添加调度器任务命令",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchAddCommandRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchAddCommandResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"cmds": [{
"jobId": "java.lang.Object",
"cmdType": "int"
}],
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int"
}
}, {
"name": "/offlineNode",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【管理端】节点下线",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchOfflineNodeRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchOfflineNodeResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int"
}
}, {
"name": "/onlineService",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【管理端】服务上线",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchOnlineServiceRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchOnlineServiceResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"serviceName": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int"
}
}, {
"name": "/offlineService",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【管理端】服务下线",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchOfflineServiceRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchOfflineServiceResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"serviceName": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int"
}
}, {
"name": "/cleanNode",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【管理端】清理节点",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchNodeCleanRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchNodeCleanResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int"
}
}, {
"name": "/cleanJob",
"method": ["POST"],
"produces": ["application/x-protobuf"],
"desc": "【管理端】清理任务",
"version": "1.0",
"parameterClassName": "com.hs.dsch.proto.DSchAdminProto.DSchJobCleanRequest",
"returnClassName": "com.hs.dsch.proto.DSchAdminProto.DSchJobCleanResponse",
"parameterTypeIdl": "DSchAdminProto.proto",
"returnTypeIdl": "DSchAdminProto.proto",
"parameterDeclare": {
"jobId": "java.lang.Object",
"nodeId": "java.lang.Object"
},
"resultDeclare": {
"resCode": "int"
}
}]
}]
}
利用生成的数据可以将文档可视化,文档数据结构解释如下:
-
一个project包含多个service,每个service包含多个method;
-
project,service以及method有一些属性用于描述自身;
-
method包含两个主要的成员,一个是入参类型以及该类型的成员(标签为parameterDeclare),一个是出参类型以及类型成员(标签为resultDeclare)。
将json描述的对象转换成protobuf的Message.Builder对象,可以实现在线自动化测试;
public static void main(String [] args) throws Exception {
String jsonString = "{\"userId\":564343,\"data\":\"你好\",\"test\":"
+ "{\"index\":4567,\"test0\":{\"p0\":11111,\"p1\":\"hello world,12434\"},"
+ "\"tests0\":[{\"p0\":11111,\"p1\":\"hello world,11111\"},{\"p0\":2222,\"p1\":\"hello world,22222\"}]},"
+ "\"ts0\":[{\"p0\":11111,\"p1\":\"hello world,12434\"}],\"et\":1}";
// 转换
Builder builder = new IDLObjectDeserializer().deserialize("com.hs.cart.proto.CartServiceProto.CartRequest", jsonString);
byte [] data = builder.build().toByteArray();
System.out.println("数据长度:" + data.length);
// 验证
CartRequest.Builder vbuilder = (CartRequest.Builder)builder;
System.out.println(vbuilder.getData() + "/" + vbuilder.getEtValue() + "/" + vbuilder.getUserId());
for (Test0 test0 : vbuilder.getTs0List()) {
System.out.println(test0.getP0() + "/" + test0.getP1());
}
for (Test0 test0 : vbuilder.getTest().getTests0List()) {
System.out.println(test0.getP0() + "/" + test0.getP1());
}
System.out.println(vbuilder.getTest().getIndex());
}