服务总线

更新时间:

1. 整体介绍

1.1. 设计目标

用于规范应用之间行为表达方式和对结果的预期。

  • 对于服务提供方来讲,通过服务标准化,能够清晰而简洁的表达本服务提供了哪些接口、定义、以及他们所应实现的具体功能,并且任何对该服务所提供的能力有依赖的应用,都必须按照这套接口来实现服务供应;

  • 对于服务依赖方来讲,(即使用该服务的应用)能够清晰而简洁的表达他所依赖的接口有哪些,分别期望这些接口完成什么样的具体功能,并且任何为其提供服务的应用,只要遵循相同的服务模型,即可实现服务提供方的替换。

1.2. 概念定义

对服务模型的定义,如下几点说明:

  1. 服务即接口。我们这里定义的服务,从概念上理解,这是一个对应用能力的抽象表达;但是从实际操作层面,服务的实际体现方式,就是RESTful风格的HTTP接口。

  2. 接口是分组的。分组的原则是能力原子化,即我们按照接口的能力范围,将一组完成功能闭环的接口标定为一组。并且,我们将这一组接口,定义为“一个服务模型”。

  3. 服务模型是受管控的。目前,每一个服务模型都是由行业小二在后台制定并发布。ISV在实践过程中可以根据实际情况,向相关小二提出调整意见。

  4. 服务模型是有版本的。一个基础服务模型,随着不用ISV、不同场景的需求,会有版本迭代。因此,唯一确定一个服务模型提供的接口信息的,是模型ID+版本。

2. 服务管控流程

image.png

3. 服务模型的管理

服务模型的定义,是由平台统一管控的。ISV在应用开发和实践中,如果需要修改或者全新定义服务模型,请联系相关人员。

4. 服务模型的声明

模型的声明分两个角度:服务模型的依赖和服务模型的提供。一个应用在正式上架前,需要声明该应用所提供的服务和所依赖的服务。模型的声明入口,见下图:image.png

4.1 服务的依赖配置

如下图所示:image.png

上图中显示,服务的依赖,是需要指定到模型下面的某一个或者多个接口的。进入配置页面,如下:image.png

4.2 服务的提供配置

如下图所示:image.png

图中,需要用户指定的,除了模型之外,还有指定模型版本和提供该服务能力的节点,如上红色区域。

5. 服务模型的调试

应用开发完成之后,如果应用依赖或者提供服务模型的能力,那势必需经过集成调试,方可上架。应用的调试分成两类:服务依赖的调试、服务提供的调试。

5.1 服务依赖的调试

当应用依赖一个服务时,它的调试过程需要有一个虚拟的服务提供者来为该应用提供服务,并且监测每一次应用的服务调用。image.png

5.2 服务提供的调试

当应用提供一个服务时,它的调试过程需要有一个虚拟的客户端,来发起对该应用该服务的调用,并且监测每一次应用的服务调用。

首先,进入AppKey > 查看,指定要调试的服务,并启动客户端,启动之后界面如下:53AFCBD3-776D-40a5-83F4-4D7C5706F56E.png

启动之后,ISV就可以进入每一个接口,模拟该接口向当前应用发起服务调试了。用户可以在调试界面看到服务调用的数据image.png

6. 服务模型的集成

在项目集成阶段,当应用之间有服务依赖关系时,需要在集成工作台,将服务的提供方①和依赖方②关联起来。image.png

7. ISV开发示例

服务模型的开发主要分为两个部分:服务提供和服务依赖。服务提供,为第三方提供标准化的服务接口;服务依赖,使用第三方提供的服务。

7.1 案例介绍

以实现停车场服务模型(模型ID为:“parking”)的API(标识符为:“qrcodePayAndPush”)为例,分别介绍如何实现一个托管应用,**服务提供方如何实现声明的服务模型的服务能力,以及服务依赖方如何调用该服务**。模型定义如下:image.png

qrcodePayAndPush接口定义如下:image.pngimage.png

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"));