服務(wù)總線
1. 整體介紹
1.1. 設(shè)計目標
用于規(guī)范應(yīng)用之間行為表達方式和對結(jié)果的預(yù)期。
對于服務(wù)提供方來講,通過服務(wù)標準化,能夠清晰而簡潔的表達本服務(wù)提供了哪些接口、定義、以及他們所應(yīng)實現(xiàn)的具體功能,并且任何對該服務(wù)所提供的能力有依賴的應(yīng)用,都必須按照這套接口來實現(xiàn)服務(wù)供應(yīng);
對于服務(wù)依賴方來講,(即使用該服務(wù)的應(yīng)用)能夠清晰而簡潔的表達他所依賴的接口有哪些,分別期望這些接口完成什么樣的具體功能,并且任何為其提供服務(wù)的應(yīng)用,只要遵循相同的服務(wù)模型,即可實現(xiàn)服務(wù)提供方的替換。
1.2. 概念定義
對服務(wù)模型的定義,如下幾點說明:
服務(wù)即接口。我們這里定義的服務(wù),從概念上理解,這是一個對應(yīng)用能力的抽象表達;但是從實際操作層面,服務(wù)的實際體現(xiàn)方式,就是RESTful風(fēng)格的HTTP接口。
接口是分組的。分組的原則是能力原子化,即我們按照接口的能力范圍,將一組完成功能閉環(huán)的接口標定為一組。并且,我們將這一組接口,定義為“一個服務(wù)模型”。
服務(wù)模型是受管控的。目前,每一個服務(wù)模型都是由行業(yè)小二在后臺制定并發(fā)布。ISV在實踐過程中可以根據(jù)實際情況,向相關(guān)小二提出調(diào)整意見。
服務(wù)模型是有版本的。一個基礎(chǔ)服務(wù)模型,隨著不用ISV、不同場景的需求,會有版本迭代。因此,唯一確定一個服務(wù)模型提供的接口信息的,是模型ID+版本。
2. 服務(wù)管控流程
3. 服務(wù)模型的管理
服務(wù)模型的定義,是由平臺統(tǒng)一管控的。ISV在應(yīng)用開發(fā)和實踐中,如果需要修改或者全新定義服務(wù)模型,請聯(lián)系相關(guān)人員。
4. 服務(wù)模型的聲明
模型的聲明分兩個角度:服務(wù)模型的依賴和服務(wù)模型的提供。一個應(yīng)用在正式上架前,需要聲明該應(yīng)用所提供的服務(wù)和所依賴的服務(wù)。模型的聲明入口,見下圖:
4.1 服務(wù)的依賴配置
如下圖所示:
上圖中顯示,服務(wù)的依賴,是需要指定到模型下面的某一個或者多個接口的。進入配置頁面,如下:
4.2 服務(wù)的提供配置
如下圖所示:
圖中,需要用戶指定的,除了模型之外,還有指定模型版本和提供該服務(wù)能力的節(jié)點,如上紅色區(qū)域。
5. 服務(wù)模型的調(diào)試
應(yīng)用開發(fā)完成之后,如果應(yīng)用依賴或者提供服務(wù)模型的能力,那勢必需經(jīng)過集成調(diào)試,方可上架。應(yīng)用的調(diào)試分成兩類:服務(wù)依賴的調(diào)試、服務(wù)提供的調(diào)試。
5.1 服務(wù)依賴的調(diào)試
當(dāng)應(yīng)用依賴一個服務(wù)時,它的調(diào)試過程需要有一個虛擬的服務(wù)提供者來為該應(yīng)用提供服務(wù),并且監(jiān)測每一次應(yīng)用的服務(wù)調(diào)用。
5.2 服務(wù)提供的調(diào)試
當(dāng)應(yīng)用提供一個服務(wù)時,它的調(diào)試過程需要有一個虛擬的客戶端,來發(fā)起對該應(yīng)用該服務(wù)的調(diào)用,并且監(jiān)測每一次應(yīng)用的服務(wù)調(diào)用。
首先,進入
,指定要調(diào)試的服務(wù),并啟動客戶端,啟動之后界面如下:啟動之后,ISV就可以進入每一個接口,模擬該接口向當(dāng)前應(yīng)用發(fā)起服務(wù)調(diào)試了。用戶可以在調(diào)試界面看到服務(wù)調(diào)用的數(shù)據(jù)
6. 服務(wù)模型的集成
在項目集成階段,當(dāng)應(yīng)用之間有服務(wù)依賴關(guān)系時,需要在集成工作臺,將服務(wù)的提供方①和依賴方②關(guān)聯(lián)起來。
7. ISV開發(fā)示例
服務(wù)模型的開發(fā)主要分為兩個部分:服務(wù)提供和服務(wù)依賴。服務(wù)提供,為第三方提供標準化的服務(wù)接口;服務(wù)依賴,使用第三方提供的服務(wù)。
7.1 案例介紹
以實現(xiàn)停車場服務(wù)模型(模型ID為:“parking”)的API(標識符為:“qrcodePayAndPush”)為例,分別介紹如何實現(xiàn)一個托管應(yīng)用,**服務(wù)提供方如何實現(xiàn)聲明的服務(wù)模型的服務(wù)能力,以及服務(wù)依賴方如何調(diào)用該服務(wù)**。模型定義如下:
qrcodePayAndPush接口定義如下:
7.2 服務(wù)提供的開發(fā)示例
需要實現(xiàn)服務(wù)模型中的API定義,應(yīng)用必須實現(xiàn)聲明的服務(wù)模型的所有的API定義,并且實現(xiàn)的API 入?yún)⒑统鰠⑿枰耆3忠恢隆?b>示例代碼:
@Slf4j
@Controller
@Configuration
@RequestMapping("/parking")
public class ParkingController {
@Resource
private ParkingService parkingService;
/**
* 發(fā)送支付二維碼到顯示屏(出場時)
*
* @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;
/**
* 設(shè)備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;
/**
* 失敗時必填,錯誤調(diào)試信息;成功時不填
*/
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;
/**
* 請求協(xié)議版本
*/
private String version;
/**
* 失敗時必填,錯誤調(diào)試信息;成功時不填
*/
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 服務(wù)依賴的開發(fā)示例
A. 開發(fā)包依賴
<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****"); // 請?zhí)顚懻_的AppKey
builderParams.setAppSecret("6726732dsfdsdsfd****"); // 請?zhí)顚懻_的AppSecret
ApacheHttpClient apacheHttpClient = new ApacheHttpClient(builderParams);
IoTApiRequest request = new IoTApiRequest();
//服務(wù)模型的API的版本,注意不是服務(wù)模型的版本。
request.setApiVer("1.0");
//如果需要登錄,設(shè)置當(dāng)前的會話的token
//設(shè)置參數(shù)
request.putParam("campusId", "testCampusId");
request.putParam("tradeNo", "tradeNoTest");
request.putParam("totalAmount", "12.2");
request.putParam("deviceUuid", "testUuid");
//請求參數(shù)域名、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"));