本部分將介紹使用spider RPC開發分散式應用的客戶端和服務端。 spider RPC中間件基於J2SE 8開發,因此需要確保伺服器上安裝了JDK 8及以上版本,不依賴於任何額外需要獨立安裝和配置的依賴程式。 註:spider RPC 1.0.1版本之前基於JDK 1.7開發,最後改為了使用JD ...
本部分將介紹使用spider RPC開發分散式應用的客戶端和服務端。
spider RPC中間件基於J2SE 8開發,因此需要確保伺服器上安裝了JDK 8及以上版本,不依賴於任何額外需要獨立安裝和配置的依賴程式。
註:spider RPC 1.0.1版本之前基於JDK 1.7開發,最後改為了使用JDK 1.8主要是出於公司內部系統對接的考慮,使用了1.8新增的Parameter類,因為內部系統需要解析參數名。
spider RPC中間件的核心設計初衷是像調用本地服務一樣調用遠程服務,能夠靈活的在運行時確定目標服務在哪台伺服器,且高效的管理上百台的大規模伺服器集群。
依賴jar包引入
spider包括下列依賴包:
點擊下載 |
spider核心包 | <dependency>
<groupId>com.ld.net.spider</groupId> <artifactId>com.ld.net.spider</artifactId> <version>1.0.X-SNAPSHOT</version> </dependency> |
點擊下載 |
Spider擴展包,比如管理、監控spider運行狀態,與服務中心交互等等 | <dependency>
<groupId>com.ld.net.spider</groupId> <artifactId>com.ld.net.spider.ext</artifactId> <version>1.0.X-SNAPSHOT</version> </dependency> |
com.ld.net.spider.sc.client.api.jar 點擊下載 |
服務中心管理模式下,客戶端提供的主要管理功能介面 | <dependency>
<groupId>com.ld.net.spider</groupId> <artifactId>com.ld.net.spider.sc.client.api</artifactId> <version>1.0.X-SNAPSHOT</version> </dependency> |
com.ld.net.spider.sc.center.api.jar 點擊下載 |
服務中心管理模式下,服務中心端提供的主要功能介面 | <dependency>
<groupId>com.ld.net.spider</groupId> <artifactId>com.ld.net.spider.sc.center.api </artifactId> <version>1.0.X-SNAPSHOT</version> </dependency> |
定義服務介面
開發spider服務的第一步是定義spider服務介面,spider服務以java interface的方式進行定義。本示例涉及POJO定義如下:
package com.medsoft.spider.api; public class Demo { private int id; private String name; private double bonus; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getBonus() { return bonus; } public void setBonus(double bonus) { this.bonus = bonus; } } public class DemoReq extends SpiderBizHead { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } package com.medsoft.spider.api; import com.ld.net.remoting.LDParam; public class DemoResp { private int errorNo; private String errorInfo; public int getErrorNo() { return errorNo; } public void setErrorNo(int errorNo) { this.errorNo = errorNo; } public String getErrorInfo() { return errorInfo; } public void setErrorInfo(String errorInfo) { this.errorInfo = errorInfo; } } package com.medsoft.spider.api; import java.util.List; import java.util.Map; import com.ld.net.spider.meta.SpiderBizHead; public class DemoQuery extends SpiderBizHead { private Map<String,String> param; private List<Demo> result; public List<Demo> getResult() { return result; } public void setResult(List<Demo> result) { this.result = result; } public Map<String,String> getParam() { return param; } public void setParam(Map<String,String> param) { this.param = param; } public void addParam(String key,String value) { this.param.put(key, value); } }
定義介面:
package com.medsoft.spider.api; import java.util.List; import com.ld.net.spider.annotation.Service; import com.ld.net.spider.annotation.ServiceModule; @ServiceModule public interface DemoDrpcpService { @Service(desc = "Drpcp修改", serviceId = "99000011") public DemoResp opDrpcpService(DemoReq req); @Service(desc = "Drpcp list查詢", serviceId = "99000012") public List<DemoResp> queryDrpcpService(DemoReq req); @Service(desc = "Drpcp分頁查詢", serviceId = "99000002") public DemoQuery queryDrpcpService1(DemoQuery req); @Service(desc = "調用其他MS", serviceId = "99000003") public String callAS(DemoQuery req); }
@ ServiceModule標識介面DemoDrpcpService為spider服務模塊,@Service定義了具體的服務。
需要註意的是,spider運行時要求所有參數必須通過單個DTO進行傳遞,否則在啟動時會出錯而終止,這更多的出於服務管理的需要而非技術的限制或性能的下降。
服務端開發
spider服務的實現和標準的j2ee開發一樣,創建一個標準的java web工程,只要定義java類實現服務介面即可,沒有任何額外的侵入性。
package com.medsoft.spider.server; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ld.net.base.utils.JsonUtils; import com.ld.net.spider.exception.SpiderException; import com.medsoft.spider.api.DemoDrpcpService; import com.medsoft.spider.api.DemoQuery; import com.medsoft.spider.api.DemoReq; import com.medsoft.spider.api.DemoResp; import com.medsoft.spider.other.api.OtherService; @Service public class DemoDrpcpServiceImpl implements DemoDrpcpService { @Autowired private OtherService otherService; @Override public DemoResp opDrpcpService(DemoReq req) { System.out.println("接收到spider調用請求: " + JsonUtils.toJson(req)); return new DemoResp(); } @Override public DemoQuery queryDrpcpService1(DemoQuery req) { System.out.println("接收到spider調用請求: " + JsonUtils.toJson(req)); return new DemoQuery(); } @Override public String callAS(DemoQuery req) { System.out.println("調用其他系統的AS"); try { return otherService.doAs(req); } catch (SpiderException e) { throw e; } } @Override public List<DemoResp> queryDrpcpService(DemoReq req) { List<DemoResp> list = new ArrayList<DemoResp>(); DemoResp e1 = new DemoResp(); DemoResp e2 = new DemoResp(); list.add(e1); list.add(e2); return list; } }
如上所示,實現非常簡單,沒有任何spider侵入性,故不再重覆講解。
需要註意的是,上述紅色字體的OtherService,該服務為標準Spring Bean服務或者微服務MS或其它子系統提供的公用業務服務,比如查詢賬戶信息,視具體而定。
客戶端開發
客戶端調用spider服務在開發上和調用標準的本地spring bean服務完全相同,創建一個標準的java web工程,只要設置目標服務自動註入就可以直接使用了,如下所示:
@Controller public class IndexAction { @Autowired private DemoDrpcpService demoDrpcpService; @RequestMapping(value="/to_pnp2_cnp1.html",method=RequestMethod.GET) public @ResponseBody String indexV(Model model,HttpServletRequest request){ DemoQuery req = new DemoQuery(); DemoReq param = new DemoReq(); req.setAppVersion("v1.1"); req.setSystemId("02"); req.setCompanyId("100001"); param.setId(8888); param.setName("zhangsan"); return JsonUtils.toJson(demoDrpcpService.queryDrpcpService1(req)); } }
直接通過功能號調用spider服務
除了上述通過註入介面方式調用spider服務外,spider運行時還支持直接通過功能號的方式調用,如下所示:
DemoReq param = new DemoReq(); param.setId(8888); param.setName("zhangsan"); param.setCompanyId(companyId); param.setSystemId(systemId); ServiceDefinition service = ServiceDefinitionContainer.getService("99000011"); try { return (DemoResp) service.getMethod().invoke(BeanManagerHelper.getBean(service.getClz()), param); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); }
兩種方式的調用效果相同。
介面包與實現包的部署
使用Spider開發的分散式系統最簡單的情況下通常具有如下的部署結構:
在複雜的生產部署中,其部署結構可能會異常複雜,如下所示:
本示例中,我們以簡單的客戶端/服務端為例介紹包的部署與配置文件的設置。
spider客戶端只需要放置定義服務介面的jar或class即可。
spider服務端需要同時放置定義服務介面的jar或class,和服務實現。一般來說,這兩者都打包在jar中而非分散的class會比較合理。
Spider配置
Spider包含一個配置文件,名稱為spider.xml,可以修改,具體位置可參見《spider概要設計-配置文件一節》,目前支持三種配置文件指定方式,在標準的maven工程下,建議將其放在src/main/resources下,作為標準配置文件的一部分。
客戶端spider.xml示例
<?xml version="1.0" encoding="UTF-8"?> <spider> <nodeName value="ANB" cloud="false" role="production" serviceCenter="0.0.0.0" appVersion="" charset="GBK" /> <plugins> <plugin pluginId="spider.localService" serviceTimeout="10000" zlibCompress="false" encrypt="false" anonymous="true" serviceProxyPackage="com.medsoft.spider.api"> <server enable="false" port="7070" reliable="false" threadCount="200" serviceExportPackage="" /> </plugin> <plugin pluginId="spider.channel"> <cluster clusterName="CNB-1" connectionSize="1"> <workNode address="127.0.0.1" port="18021" /> </cluster> </plugin> <plugin pluginId="spider.filter"> </plugin> </plugins> <routeItems> <routeItem serviceId="99*" clusterName="CNB-1" /> <!-- <routeItem serviceId="*" appVersion="" subSystemId="" systemId="" companyId="" clusterName="spider-server" /> --> </routeItems> </spider>
上述配置中,紅色部分是與客戶端直接相關的配置。
服務端spider.xml示例
<?xml version="1.0" encoding="UTF-8"?> <spider> <nodeName value="MSNP-1" cloud="false" role="production" serviceCenter="0.0.0.0" appVersion="" serviceDefineType="spider" needLdPackAdapter="false" charset="GBK"/> <plugins> <plugin pluginId="spider.localService" serviceTimeout="10000" zlibCompress="false" encrypt="false" anonymous="true" serviceProxyPackage=""> <server enable="true" port="18051" reliable="false" threadCount="200" serviceExportPackage="com.medsoft.spider.api" /> </plugin> <plugin pluginId="spider.channel"> </plugin> <plugin pluginId="spider.filter"> </plugin> </plugins> <routeItems> <routeItem serviceId="*" clusterName="spider.localService" /> <!-- <routeItem serviceId="*" appVersion="" subSystemId="" systemId="" companyId="" clusterName="spider-server" /> --> </routeItems> </spider>
上述配置中,紅色部分是與客戶端直接相關的配置。
服務端配置註意事項
spider啟動時會進行下列自檢操作:
1、在/tmp/spider/下檢查是否存在${nodeName}.pid文件,如果存在,則說明本伺服器上存在同名已啟動spider實例,不允許啟動;
2、運行伺服器模式時,檢查本節點spider.xml中定義的伺服器埠號是否已經被占用,如果已經被占用,則提示埠號已經被占用,不允許啟動;
運行方式
當前版本spider支持運行於標準java應用程式和web容器下兩種模式,他們提供完全相同的核心服務。在運行於標準java程式模式下時,spider提供的RESTFUL管理控制台和API將不可用。
web.xml配置
客戶端和服務端的web.xml配置要求相同,如不需要啟用web監控,只需要包含如下即可:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spider-base-service.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> 如需啟用web監控,則還需要包含如下: <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:spider-base-web.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
啟動運行
上述步驟均完成後,就可以啟動spider服務端和客戶端進行驗證了。Spider服務端和客戶端的啟動順序無關緊要,spider運行時會每隔指定間隔自動進行檢測並嘗試建立斷開和尚未建立的連接。