服务总线
1. 整体介绍
1.1. 设计目标
用于规范应用之间行为表达方式和对结果的预期。
对于服务提供方来讲,通过服务标准化,能够清晰而简洁的表达本服务提供了哪些接口、定义、以及他们所应实现的具体功能,并且任何对该服务所提供的能力有依赖的应用,都必须按照这套接口来实现服务供应;
对于服务依赖方来讲,(即使用该服务的应用)能够清晰而简洁的表达他所依赖的接口有哪些,分别期望这些接口完成什么样的具体功能,并且任何为其提供服务的应用,只要遵循相同的服务模型,即可实现服务提供方的替换。
1.2. 概念定义
对服务模型的定义,如下几点说明:
服务即接口。我们这里定义的服务,从概念上理解,这是一个对应用能力的抽象表达;但是从实际操作层面,服务的实际体现方式,就是RESTful风格的HTTP接口。
接口是分组的。分组的原则是能力原子化,即我们按照接口的能力范围,将一组完成功能闭环的接口标定为一组。并且,我们将这一组接口,定义为“一个服务模型”。
服务模型是受管控的。目前,每一个服务模型都是由行业小二在后台制定并发布。ISV在实践过程中可以根据实际情况,向相关小二提出调整意见。
服务模型是有版本的。一个基础服务模型,随着不用ISV、不同场景的需求,会有版本迭代。因此,唯一确定一个服务模型提供的接口信息的,是模型ID+版本。
2. 服务管控流程
3. 服务模型的管理
服务模型的定义,是由平台统一管控的。ISV在应用开发和实践中,如果需要修改或者全新定义服务模型,请联系相关人员。
4. 服务模型的声明
模型的声明分两个角度:服务模型的依赖和服务模型的提供。一个应用在正式上架前,需要声明该应用所提供的服务和所依赖的服务。模型的声明入口,见下图:
4.1 服务的依赖配置
如下图所示:
上图中显示,服务的依赖,是需要指定到模型下面的某一个或者多个接口的。进入配置页面,如下:
4.2 服务的提供配置
如下图所示:
图中,需要用户指定的,除了模型之外,还有指定模型版本和提供该服务能力的节点,如上红色区域。
5. 服务模型的调试
应用开发完成之后,如果应用依赖或者提供服务模型的能力,那势必需经过集成调试,方可上架。应用的调试分成两类:服务依赖的调试、服务提供的调试。
5.1 服务依赖的调试
当应用依赖一个服务时,它的调试过程需要有一个虚拟的服务提供者来为该应用提供服务,并且监测每一次应用的服务调用。
5.2 服务提供的调试
当应用提供一个服务时,它的调试过程需要有一个虚拟的客户端,来发起对该应用该服务的调用,并且监测每一次应用的服务调用。
首先,进入
,指定要调试的服务,并启动客户端,启动之后界面如下:启动之后,ISV就可以进入每一个接口,模拟该接口向当前应用发起服务调试了。用户可以在调试界面看到服务调用的数据
6. 服务模型的集成
在项目集成阶段,当应用之间有服务依赖关系时,需要在集成工作台,将服务的提供方①和依赖方②关联起来。
7. ISV开发示例
服务模型的开发主要分为两个部分:服务提供和服务依赖。服务提供,为第三方提供标准化的服务接口;服务依赖,使用第三方提供的服务。
7.1 案例介绍
以实现停车场服务模型(模型ID为:“parking”)的API(标识符为:“qrcodePayAndPush”)为例,分别介绍如何实现一个托管应用,**服务提供方如何实现声明的服务模型的服务能力,以及服务依赖方如何调用该服务**。模型定义如下:
qrcodePayAndPush接口定义如下:
7.2 服务提供的开发示例
需要实现服务模型中的API定义,应用必须实现声明的服务模型的所有的API定义,并且实现的API 入参和出参需要完全保持一致。示例代码:
@Slf4j
@Controller
@Configuration
@RequestMapping("/parking")
public class ParkingController {
@Resource
private ParkingService parkingService;
/**
* 发送支付二维码到显示屏(出场时)
*
* @param qrcodeRequest
* @return
*/
@PostMapping("/qrcodePayAndPush")
public @ResponseBody
BaseResponse<PushQrcodeResponse> receiveMessage(
@RequestBody BaseRequest<PushQrcodeRequest> qrcodeRequest) {
System.out.println("qrcodeRequest info: " + qrcodeRequest.toString());
PushQrcodeResponse pushQrcodeResponse = new PushQrcodeResponse();
pushQrcodeResponse.setQrcodeUrl("www.****.com/qrcodePayAndPush");
BaseResponse<PushQrcodeResponse> response = new BaseResponse<>();
response.setId(qrcodeRequest.getId());
response.setData(pushQrcodeResponse);
return response;
}
}
public class PushQrcodeRequest implements Serializable {
private static final long serialVersionUID = 1L;
/**
* deviceUuid
*/
private String campusId;
/**
* 订单号
*/
private String tradeNo;
/**
* 需要支付的金额
*/
private String totalAmount;
/**
* 设备uuid
*/
private String deviceUuid;
public String getCampusId() {
return campusId;
}
public void setCampusId(String campusId) {
this.campusId = campusId;
}
public String getTradeNo() {
return tradeNo;
}
public void setTradeNo(String tradeNo) {
this.tradeNo = tradeNo;
}
public String getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(String totalAmount) {
this.totalAmount = totalAmount;
}
public String getDeviceUuid() {
return deviceUuid;
}
public void setDeviceUuid(String deviceUuid) {
this.deviceUuid = deviceUuid;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"campusId\":\"")
.append(campusId == null ? "" : campusId).append('\"');
sb.append(",\"tradeNo\":\"")
.append(tradeNo == null ? "" : tradeNo).append('\"');
sb.append(",\"totalAmount\":")
.append(totalAmount);
sb.append(",\"deviceUuid\":\"")
.append(deviceUuid == null ? "" : deviceUuid).append('\"');
sb.append('}');
return sb.toString();
}
}
public class PushQrcodeResponse implements Serializable {
private static final long serialVersionUID = 1L;
/**
* qrcodeUrl
*/
private String qrcodeUrl;
public String getQrcodeUrl() {
return qrcodeUrl;
}
public void setQrcodeUrl(String qrcodeUrl) {
this.qrcodeUrl = qrcodeUrl;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"qrcodeUrl\":\"")
.append(qrcodeUrl == null ? "" : qrcodeUrl).append('\"');
sb.append('}');
return sb.toString();
}
}
public class BaseResponse<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* request里的全局唯一id透传
*/
private String id;
/**
* code
*/
private int code = 200;
/**
* 失败时必填,错误调试信息;成功时不填
*/
private String message;
/**
* 失败时必填,用户可理解语言描述的错误信息;成功时不填
*/
private String localizedMsg;
/**
* 成功时必填,失败时选填
*/
private T data;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getLocalizedMsg() {
return localizedMsg;
}
public void setLocalizedMsg(String localizedMsg) {
this.localizedMsg = localizedMsg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"id\":\"")
.append(id == null ? "" : id).append('\"');
sb.append(",\"code\":")
.append(code);
sb.append(",\"message\":\"")
.append(message == null ? "" : message).append('\"');
sb.append(",\"localizedMsg\":\"")
.append(localizedMsg == null ? "" : localizedMsg).append('\"');
sb.append(",\"data\":")
.append(data);
sb.append('}');
return sb.toString();
}
}
public class BaseRequest<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* request里的全局唯一id透传
*/
private String id;
/**
* 请求协议版本
*/
private String version;
/**
* 失败时必填,错误调试信息;成功时不填
*/
private Map<String, Object> request;
/**
* 失败时必填,用户可理解语言描述的错误信息;成功时不填
*/
private T params;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public Map<String, Object> getRequest() {
return request;
}
public void setRequest(Map<String, Object> request) {
this.request = request;
}
public T getParams() {
return params;
}
public void setParams(T params) {
this.params = params;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"id\":\"")
.append(id == null ? "" : id).append('\"');
sb.append(",\"version\":\"")
.append(version == null ? "" : version).append('\"');
sb.append(",\"request\":")
.append(request);
sb.append(",\"params\":")
.append(params);
sb.append('}');
return sb.toString();
}
}
7.3 服务依赖的开发示例
A. 开发包依赖
<dependency>
<groupId>com.aliyun.api.gateway</groupId>
<artifactId>sdk-core-java</artifactId>
<version>1.6.0.3</version>
</dependency>
B. 示例代码
HttpClientBuilderParams builderParams = new HttpClientBuilderParams();
builderParams.setAppKey("123****"); // 请填写正确的AppKey
builderParams.setAppSecret("6726732dsfdsdsfd****"); // 请填写正确的AppSecret
ApacheHttpClient apacheHttpClient = new ApacheHttpClient(builderParams);
IoTApiRequest request = new IoTApiRequest();
//服务模型的API的版本,注意不是服务模型的版本。
request.setApiVer("1.0");
//如果需要登录,设置当前的会话的token
//设置参数
request.putParam("campusId", "testCampusId");
request.putParam("tradeNo", "tradeNoTest");
request.putParam("totalAmount", "12.2");
request.putParam("deviceUuid", "testUuid");
//请求参数域名、path、request
String host = "service-mesh.api-iot.cn-shanghai.aliyuncs.com";
String path = "/parking/qrcodePayAndPush";
System.out.println(JSON.toJSONString(request));
ApiRequest apiRequest = new ApiRequest(HttpScheme.HTTP, host,
HttpMethod.POST_BODY, path, JSON.toJSONBytes(request));
apiRequest.setHttpConnectionMode(HttpConnectionModel.MULTIPLE_CONNECTION);
ApiResponse response = apacheHttpClient.sendSyncRequest(apiRequest);
System.out.println(request.getId());
System.out.println(
"response code = " + response.getCode() + " response message = " + response.getMessage()
+ " response content = " + new String(response.getBody(),
"utf-8"));