網(wǎng)關(guān)輔助類使用說明
本文對網(wǎng)關(guān)中用到的相關(guān)輔助類,包括攔截器類、MobileRpcHolder,以及網(wǎng)關(guān)錯誤碼的使用進行說明。
實現(xiàn)攔截器功能
攔截器只適用于非 HTTP 類型服務。
mobilegw-unify-spi-adapter.jar
實際上是通過 Java 的反射調(diào)用業(yè)務方法,即OperatioinType
所指定的方法。在方法調(diào)用的過程中,業(yè)務方可以實現(xiàn) SPI 包中定義的攔截器,從而實現(xiàn)擴展。
網(wǎng)關(guān)的 SPI 包定義了兩個攔截器:AbstractMobileServiceInterceptor
抽象類和 MobileServiceInterceptor
接口。
AbstractMobileServiceInterceptor
MobileServiceInterceptor
主要提供了四個方法,分別是 beforeInvoke
、afterInvoke
(分為兩種:一種入?yún)闃I(yè)務返回的 Object;另一種入?yún)?Object 轉(zhuǎn)成的 JSON string)、throwsInvoke
和 getOrder
。
如上圖所示,攔截器主要在以下三種情況下進行攔截:
方法調(diào)用前:即
beforeInvoke
方法,該方法有返回值。一旦該方法的返回值不為空,那么網(wǎng)關(guān)認定攔截成功,將會跳過剩余攔截器的beforeInvoke
方法,同時跳過調(diào)用業(yè)務方的方法,直接進入攔截器的afterInvoke
方法。方法調(diào)用后: 即
afterInvoke
方法。afterInvoke
有兩種,一種入?yún)?Object,即業(yè)務方返回的對象,該方法沒有返回值,所有的攔截器的該方法都會執(zhí)行;另一種入?yún)?Object 轉(zhuǎn)成的 JSON string,該方法可以改變傳入的 JSON 數(shù)據(jù)并返回。一旦返回值不為空,那么網(wǎng)關(guān)認定攔截成功,后續(xù)的攔截器將被忽略。方法出現(xiàn)異常:即
throwsInvoke
方法。該方法沒有返回值,所有攔截器的該方法都會被執(zhí)行。在業(yè)務方出現(xiàn)異常時會被調(diào)用。
MobileServiceInterceptor
MobileServiceInterceptor
繼承了框架的 Ordered
接口,因此,業(yè)務方實現(xiàn)的攔截器還可以通過實現(xiàn) getOrder
方法指定執(zhí)行順序,設(shè)置的數(shù)值越小,執(zhí)行的優(yōu)先級越高;設(shè)置的數(shù)值越大,執(zhí)行的優(yōu)先級越低。
使用示例
編碼自己的攔截器類,繼承
AbstractMobileServiceInterceptor
類,或者實現(xiàn)MobileServiceInterceptor
接口。public class MyInterceptor implements MobileServiceInterceptor { /* 參數(shù)說明 method:即業(yè)務方的方法(@OperatioinType 定義的方法) args: 一個對象數(shù)組,即業(yè)務方方法的傳入?yún)?shù),傳入?yún)?shù)個數(shù)即等于數(shù)組大小。 使用時業(yè)務方根據(jù)需要進行類型轉(zhuǎn)換。 bean: 即業(yè)務方的接口實例。 返回值說明: Object:可以在攔截器中返回數(shù)據(jù),一旦返回值不為空,則網(wǎng)關(guān)認為已被攔截,就不會再調(diào)用業(yè)務方法 同時,直接跳過其他攔截器的 beforeInvoke 方法,執(zhí)行攔截器中的 afterInvoke 方法。 */ @Override public Object beforeInvoke(Method method, Object[] args, Object target) { //Do Something return null; } /* *參數(shù)說明 *returnValue: 業(yè)務方法返回的對象 * 其它參數(shù)同上 */ @Override public void afterInvoke(Object returnValue, Method method, Object[] args, Object target) { //注意:這里入?yún)⑹菢I(yè)務方返回的 Object } @Override public String afterInvoke(String returnJsonValue, Method method, Object[] args, Object target) { //注意:這里入?yún)⑹怯蓸I(yè)務方返回的 object,轉(zhuǎn)換而成的 JSON 格式的 string //可以返回新的 JSON 數(shù)據(jù) return null; } @Override public void throwsInvoke(Throwable t, Method method, Object[] args, Object target) { } @Override public int getOrder() { //最高級(數(shù)值最小)和最低級(數(shù)值最大)。 return 0; } }
發(fā)布實現(xiàn)的類
MyInterceptor
,成為 Bean。Spring Boot:直接在該類加注解
@service
。@service public class MyInterceptor implements MobileServiceInterceptor{}
Spring:在配置的
xml
文件聲明。<bean id="myInterceptor" class="com.xxx.xxx.MyInterceptor"/>
MobileRpcHolder 輔助類
MobileRpcHolder
是 mobilegw-unify-spi-adapter.jar
中提供的一個靜態(tài)輔助類,該類定義了一個請求過程中的相關(guān)信息,最主要的定義如下:
Map<String, String> session 保存請求的 session
Map<String, String> header 保存請求的頭部相關(guān)信息
Map<String, String> context 保存網(wǎng)關(guān)調(diào)用的上下文信息
String operationType 保存此次請求的 operationType
在業(yè)務方的服務(即 OperationType
)被調(diào)用之前,SPI 服務會根據(jù)網(wǎng)關(guān)轉(zhuǎn)發(fā)的請求 MobileRpcRequest
去設(shè)置 MobileRpcHolder
中的信息。在調(diào)用業(yè)務方服務之后這些信息會被清除。
MobileRpcHolder
的生命周期為整個服務的調(diào)用過程,調(diào)用后清除。
業(yè)務方也可以根據(jù)需要去設(shè)置這些信息,這些信息會在調(diào)用業(yè)務的服務過程中一直存在,在調(diào)用過程中業(yè)務服務可以獲取這些信息。具體的設(shè)置可以通過攔截器,在方法調(diào)用前后動態(tài)地修改 MobileRpcHolder
中保存的信息。
以下通過例子說明 MobileRpcHolder
如何使用。
使用示例
這里以修改和獲取 session 為例。
修改 session。 創(chuàng)建攔截器,具體過程參考上面的攔截器示例。下面以在方法調(diào)用前攔截為例:
@Override public Object beforeInvoke(Method method, Object[] args, Object target) { Map<String, String> session = MobileRpcHolder.getSession(); session.put("key_test", "value_test"); MobileRpcHolder.setSession(session); }
這樣就能修改
MobileRpcHolder
中的 session 信息。獲取 session。 業(yè)務方在自己定義的服務中可以獲取 session 信息。
@OperationType("com.alipay.account.query") public String mock2(String s) { Map<String, String> session = MobileRpcHolder.getSession(); }
其他信息(如 header、context)的修改和獲取方式同上。
// 獲取 header 所有信息 Map<String,String> headers = MobileRpcHolder.getHeaders(); // 這里上下文信息指的是請求中的上下文信息 Map<String,String> context = MobileRpcHolder.getRequestCtx(); // 獲取 OperationType String opt = MobileRpcHolder.getOperationType();
使用網(wǎng)關(guān)錯誤碼
移動網(wǎng)關(guān)有自己的一套錯誤碼規(guī)范,詳見 網(wǎng)關(guān)結(jié)果碼說明。
需要注意 BizException 6666
,此錯誤是業(yè)務出現(xiàn)異常后,網(wǎng)關(guān)會拋出的異常。
如果想要在出現(xiàn)具體錯誤時,返回其他錯誤碼,可以通過拋出 RpcException(ResultEnum resultCode)
來控制 RPC 層的錯誤,比如 resultCode=1001
,會返回給客戶端“沒有權(quán)限訪問”。
代碼示例
@Override
public String mock2(String s) throws RpcException {
try{
test();
}catch (Exception e){
throw new RpcException(IllegalArgument);
}
return "11111111";
}
自定義錯誤碼
如果想使用自定義錯誤碼,那么在調(diào)用業(yè)務方法時不能往外拋異常。
業(yè)務方法只要出現(xiàn)異常,就會返回狀態(tài)碼 6666。同時客戶端收到該狀態(tài)碼,即認為服務出錯,不會去解析業(yè)務返回的數(shù)據(jù)。客戶端只有在接收到 1000 狀態(tài)碼時,才會去解析返回的數(shù)據(jù)。
具體做法是,服務端和客戶端約定好具體的錯誤碼,然后在調(diào)用業(yè)務方法時捕獲(catch)所有的異常,將自定義錯誤碼放在返回的數(shù)據(jù)中。這樣即使業(yè)務出現(xiàn)異常,網(wǎng)關(guān)也會返回 1000 成功。同時客戶端去解析返回的數(shù)據(jù),提取自定義錯誤碼。