spider RPC入门指南
请访问https://git.oschina.net/zhjh256/io-spider获取最新更新。
本部分将介绍使用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运行时会每隔指定间隔自动进行检测并尝试建立断开和尚未建立的连接。