remoting
介紹
遠程服務調用組件
1.遠程服務調用組件是基于Java SPI(Service Provider Interface)機制實現(xiàn)贴硫,具有插件式棍弄,高度可擴展该园,集成使用簡單等特點兆解。
2.獨創(chuàng)的XML配置格式及配套解析方法披摄,讓遠程接口配置更為簡單亲雪,處理更為靈活,
3.組件提供統(tǒng)一的遠程服務調用API行疏,解決了遠程服務調用代碼分散匆光,實現(xiàn)各異套像,配置硬編碼等問題酿联。
4.同時統(tǒng)一抽象的調用器接口使得每個服務的具體通信方式和格式對使用者都是透明的,可通過配置不同的調用器類來支持相應的調用策略。
5.遠程服務調用組件贞让,屏蔽了具體的通信方式和數(shù)據(jù)格式轉換細節(jié)周崭,程序員只需要傳入?yún)?shù)對象和服務ID即可。
軟件架構
類關系模型
基于XML配置文件喳张,配置遠程接口续镇,提供統(tǒng)一遠程調用API,解決了遠程服務調用代碼分散销部,配置硬編碼在代碼中摸航,開發(fā)效率低下的問題。與現(xiàn)在使用的大多數(shù)方法相比舅桩,本方法簡化了遠程服務調用流程酱虎,配置靈活,開發(fā)效率大大提高,具體內容如下:
- 獨創(chuàng)XML配置格式:
<services>
<http-endpoint id="http_credits" service-addr="/v1/integral/"type="https">
<host address="www.test.com" port="" appKey="30a10e21" secretKey="43351af641be41e08d398f6952d4b8c1" livemode="0" scope="INTEGRAL" />
</http-endpoint>
<import service-id="add" api="add" endpoint-ref="http_credits">
<url-param name="accesstoken">#accessToken</url-param>
<data-param name="appid">#appKey</data-param>
<data-param name="livemode">#livemode</data-param>
</import>
</services>
XML解析模塊:系統(tǒng)啟動時,讀取XML配置文件擂涛,經過XML文件格式校驗读串,節(jié)點完整性校驗,節(jié)點數(shù)據(jù)格式合法性校驗撒妈,解析等過程恢暖,最終將XML信息轉換為系統(tǒng)內部接口服務元數(shù)據(jù)信息,保存在內存中狰右,供下一步使用杰捂。
服務注冊模塊:完成XML解析之后,服務注冊模塊棋蚌,讀取接口服務元數(shù)據(jù)信息琼娘,將原數(shù)據(jù)信息轉換為服務調用模塊需要的接口服務信息格式,保存在內存中附鸽,供服務調用模塊使用脱拼。
接口服務調用模塊:提供了統(tǒng)一的遠程服務調用接口,程序根據(jù)服務ID定位到已經注冊的遠程服務接口坷备,傳入請求參數(shù)熄浓,即可完成遠程服務的調用,屏蔽了不同服務接口省撑,請求方式赌蔑,參數(shù)格式,協(xié)議類型等差異竟秫,讓使用更為簡單娃惯,開發(fā)效率更高。
服務響應處理模塊:接口服務調用模塊完成服務調用后肥败,返回信息將由此模塊進行統(tǒng)一處理趾浅,將不同接口服務響應數(shù)據(jù)格式轉換為統(tǒng)一的接口響應格式愕提,也可根據(jù)不同接口配置不同的響應數(shù)據(jù)處理(擴展開發(fā)),屏蔽了響應數(shù)據(jù)格式差異皿哨。
安裝教程
-
Maven工程導入方式:pom.xml 文件添加如下依賴
<dependency> <groupId>com.remoting</groupId> <artifactId>remoting-core</artifactId> <version>1.0.0</version> </dependency>
-
jar包引入方式:導入以下包到工程
remoting-api-1.0.0.jar remoting-core-1.0.0.jar remoting-tools-1.0.0.jar
使用說明
-
配置:以jar包引入方式浅侨,需要配置remoting.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd"> <!-- 遠程服務調用器 --> <bean id="remoteServiceExecutor" class="com.remoting.core.http.HttpRemoteServiceExecutor"> <!-- 構造函數(shù):遠程服務配置 --> <constructor-arg ref="remoteSetting" /> </bean> <!-- 遠程服務配置 --> <bean id="remoteSetting" class="com.remoting.api.RemoteSetting"> <!-- 遠程服務配置文件路徑 --> <property name="configLocation" value="service-import*.xml" /> <!-- 連接池最大并發(fā)連接數(shù) --> <property name="maxTotal" value="300" /> <!-- 單路由最大并發(fā)數(shù) --> <property name="defaultMaxPerRoute" value="50" /> <!-- 數(shù)據(jù)傳輸處理時間(毫秒) --> <property name="socketTimeout" value="4000" /> <!-- 建立連接的timeout時間(毫秒) --> <property name="connectionTimeout" value="3000" /> <!-- 從連接池中獲取連接的timeout時間(毫秒) --> <property name="connectionRequestTimeout" value="1000" /> </bean> </beans>
-
遠程服務注冊配置
<?xml version="1.0" encoding="UTF-8"?> <services> <!-- 注意:accessToken,livemode,appKey,secretKey 為系統(tǒng)變量,以#開頭使用证膨,使用后節(jié)點的值將會被替換為系統(tǒng)生成的值 --> <http-endpoint id="http_personalizedRecommend" service-addr="/CHiQ3/launcher/" type="http"> <!-- 服務器地址 <host address="chiq3.chiq-cloud.com" />--> <!-- 測試服務器地址 --> <host address="chiq3.test-cloud.com" port="" /> </http-endpoint> <!-- 獲取子類目個性化推薦 --> <import service-id="together" api="together" endpoint-ref="http_personalizedRecommend" request-type="post" ></import> </services>
-
配置參數(shù)說明
注意:accessToken,livemode,appKey 為系統(tǒng)變量如输,以#開頭使用,使用后節(jié)點的值將會被替換為系統(tǒng)生成的值
對應配置文件說明:
http-endpoint 節(jié)點
屬性
id:服務地址節(jié)點ID,全局唯一央勒。
Service-addr:路徑不见。
Type:類型。
Host子點:
屬性
address:地址崔步。
port:端口脖祈。
appKey:應用的唯一標示
secretKey:安全碼
livemode:模式
scope:作用域
http-header 節(jié)點
屬性
id:服務地址節(jié)點ID,全局唯一。
charset:編碼類型刷晋。
Header子點:
屬性
name:header鍵盖高。
Import 節(jié)點:要導入的接口
屬性
Service-id:服務ID,全局唯一眼虱。
Api: 即積分系統(tǒng)發(fā)布的接口名稱喻奥。
Endpoint-ref:服務地址配置引用ID。
Header-ref:http請求頭信息配置引用ID捏悬。
request-type:請求方式(post,get)撞蚕,默認post。
子節(jié)點
url-param:需要添加到URL中的參數(shù)配置过牙。
data-param:需要添加到請求參數(shù)中的參數(shù)配置甥厦。
注意:取值支持SpingEL表達式,需在請求參數(shù)中配置該值寇钉,如<!-- 積分查詢 --> <import service-id="query" api="" endpoint-ref="http_credits" request-type="get"> <url-param name="accesstoken">#accessToken</url-param> <url-param name="appid">#appKey</url-param> <url-param name="livemode">#livemode</url-param> </import>
Key 也支持SpingEL表達式:根據(jù)配置的EL表達式找到對應的節(jié)點并添加對應的字段(要添加的節(jié)點必須存在)如
<!-- 推送消息 -->
<import service-id="pushMsg" api="pushMsg" endpoint-ref="http_mag">
<data-param name="apikey">#appKey</data-param>
<data-param name="secretkey">#secretKey</data-param>
<data-param name="mType">THIRD</data-param>
<data-param name="apiversion">1.0</data-param>
<data-param name="['tag']['online']">0</data-param>
<data-param name="['tag']['userflag']">2</data-param>
<data-param name="['tag']['target']['condition']">AND</data-param>
</import>
特別說明:
- url-param:需要添加到URL中的參數(shù)配置刀疙。
如上例中的:
```
<url-param name="accesstoken">#accessToken</url-param>
```
? 對應積分系統(tǒng)發(fā)布的接口規(guī)范中,url部分:
```
https://www.xxx.com?accesstoken=xxx
```
其中url-name 節(jié)點中的 name屬性對應的值為url中的accesstoken(注意大小寫與url中保持一致)扫倡。
accessToken 則表示引用系統(tǒng)變量accessToken谦秧,系統(tǒng)自動識別,根據(jù)endpoint-ref引用配置中host配置(appKey, secretKey, scope)撵溃,以及當前import節(jié)點屬性api的值疚鲤,生成accessToken。
-
data-param:需要添加到請求參數(shù)中的參數(shù)配置缘挑。
如上例中的:<url-param name="appid">#appKey</url-param> <url-param name="livemode">#livemode</url-param>
對應積分系統(tǒng)發(fā)布的接口規(guī)范中集歇,正文部分相應的字段。
像這種會根據(jù)服務器環(huán)境變化而變化语淘,且在請求參數(shù)中的參數(shù)诲宇,可以用此節(jié)點配置际歼,配置后,調用程序中就不需要再設置焕窝。
其中url-name 節(jié)點中的 name屬性對應的值為接口規(guī)范請求參數(shù)中的key。
-
url-param 维贺,data-param:
取值支持SpingEL表達式它掂,需在請求參數(shù)中配置該值。
如:<url-param name="token]">['token']</data-param>
Key EL表達式
<data-param name="['tag']['online']">0</data-param>
Header-ref:
http請求頭信息引用ID溯泣,如果不設置則使用組件默認值:
即:Content-Type:application/json虐秋,編碼為:UTF-8
-
程序調用
package com.remoting; import com.remoting.api.RemoteServiceExecutor; import com.remoting.api.RemoteSetting; import com.remoting.api.spi.executor.RemoteServiceExecutorFactory; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; /** * Unit test for simple App. */ public class RemotingTest extends TestCase { private final Logger logger = LoggerFactory.getLogger(RemotingTest.class); private RemoteServiceExecutor remoteExecutor; protected void setUp() throws Exception { remoteExecutor = remoteExecutor(); } private RemoteServiceExecutor remoteExecutor(){ return RemoteServiceExecutorFactory.create(); } /** * 構建遠程服務配置 * <p>說明:</p> * <li></li> * @author DuanYong * @return * @since 2017年7月31日下午4:45:39 */ private RemoteSetting createRemoteSetting() { RemoteSetting remoteSetting = new RemoteSetting(); remoteSetting.setConfigLocation("remoting/service-import*.xml"); remoteSetting.setConnectionRequestTimeout(5 * 1000); remoteSetting.setConnectionTimeout(3 * 1000); remoteSetting.setDefaultMaxPerRoute(50); remoteSetting.setSocketTimeout(4 * 1000); remoteSetting.setMaxTotal(300); return remoteSetting; } /** * Create the test case * * @param testName * name of the test case */ public RemotingTest(String testName) { super(testName); } /** * @return the suite of tests being tested */ public static Test suite() { return new TestSuite(RemotingTest.class); } /** * Rigourous Test :-) */ public void testApp() { // Map<String, Object> param = new HashMap<String, Object>(); // param.put("mac", "18-99-f5-5d-71-c7"); // param.put("sversion", "ZLM65HiS2_0.00094"); // param.put("img_size", "300,564"); // param.put("keyword", "tv"); // Object resultObj = remoteExecutor.execute("together", param); // assertNotNull(resultObj); Map<String, Object> param = new HashMap<String, Object>(); param.put("billUserId", "2088102971016535"); param.put("startTime", "2019-02-18"); param.put("endTime", "2019-02-19"); param.put("ctoken", "u6vanf_DNIG55OWM"); Object resultObj = remoteExecutor.execute("tradeListQuery", param); logger.info(resultObj.toString()); System.out.println(resultObj.toString()); assertNotNull(resultObj); } public void testTogether() { Map<String, Object> param = new HashMap<String, Object>(); param.put("mac", "18-99-f5-5d-71-c7"); param.put("sversion", "ZLM65HiS2_0.00094"); param.put("img_size", "300,564"); param.put("keyword", "tv"); Object resultObj = remoteExecutor.execute("together", param); assertNotNull(resultObj); } }
項目信息
路漫漫其修遠兮,吾將上下而求索
碼云:https://gitee.com/javacoo/remoting
QQ:164863067
作者/微信:javacoo
郵箱:xihuady@126.com