一.服务端
WEB-INF/rpc-servlet.xml
<bean id="blogInfoService" class="com.duowan.common.rpc.fortest.api.BlogInfoServiceImpl"/> <!-- 服务发布 --> <bean class="com.duowan.common.rpc.server.RPCServiceExporter"> <property name="serviceInterface" value="com.duowan.common.rpc.fortest.api.BlogInfoService" /> <property name="service" ref="blogInfoService"/> </bean>
WEB-INF/web.xml
<servlet> <servlet-name>rpc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rpc</servlet-name> <url-pattern>/rpc/*</url-pattern> </servlet-mapping>
二.客户端
<bean name="userWebService" class="com.duowan.common.rpc.client.RPCProxyFactoryBean"> <property name="serviceUrl" value="http://localhost:6060/rpc/UserWebService"/> <property name="serviceInterface" value="com.duowan.common.rpc.fortestinvoker.UserWebService" /> </bean>
客户端使用
com.duowan.common.rpc.fortestinvoker.UserWebService userWebService = (UserWebService )applicationContext.getBean('userWebService');
三.maven依赖
<!-- 兼容性: 2.0的服务端兼容1.0,2.0客户端; 1.0的客户端不兼容2.0的服务端 --> <dependency> <groupId>com.duowan.common</groupId> <artifactId>duowan-common-rpc</artifactId> <version>2.0.0</version> </dependency> <!-- json --> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-core-asl</artifactId> <version>1.9.2</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.2</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-jaxrs</artifactId> <version>1.9.2</version> </dependency> <!-- apache commons --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>commons-httpclient</groupId> <artifactId>commons-httpclient</artifactId> <version>3.1</version> </dependency>
四.测试
比如有下面一个服务端方法
public interface BlogInfoService { Blog findSingleBlog(String group,String blogId); public BlogQuery returnBlogQuery(BlogQuery query); } public class BlogQuery { private String username; private String password; private int age; // ... property get and set method }
那么可以采用如下 URL进行访问测试:
1. http://localhost:8080/rpc/BlogInfoService/findSingleBlog?__params=group;blogId 2. http://localhost:8080/rpc/BlogInfoService/findSingleBlog?group=2222&blogId=4444 对象参数传递: 1. http://localhost:8080/services/BlogInfoService/returnBlogQuery?username=1&password=100
五.返回结果控制
通过URL参数: format=json|js来控制
1.返回Json(默认)
请求
http://localhost:6060/services/BlogInfoService/findDate?__format=json
返回
{"result":199999999,"errno":null,"error":null}
2.返回Jsonp(用于解决JavaScript跨域)
请求
http://localhost:6060/services/BlogInfoService/findDate?__format=jsonp&__jsoncallback=findDateCallback
返回
findDateCallback({"result":199999999,"errno":null,"error":null})
实际调用
<html> <head> <script src="http://code.jquery.com/jquery-latest.js"></script> </head> <body> <script> $.getJSON("http://openuic.game.yy.com/openrpc/UserGameRecommendWebService/listUserGameRecommend?__format=jsonp&__jsoncallback=?&passport=xiaolove0806", { format: "json" }, function(data) { alert(data.result); });</script> </body> </html>
JQuery Jsonp应用: Jquery应用JSONP
其它特性
1.客户端exception处理
如果服务端抛出 com.duowan.common.rpc.WebServiceException,则客户端可以try catch这个异常,服务端的任何异常都会转换为这个WebServiceException
切换行号显示
1 public class WebServiceException extends RuntimeException { 2 /** 未知错误 as HTTP 500 */ 3 public static String UNKNOW_ERROR = "UNKNOW_ERROR"; 4 /** 非法参数 as HTTP SC_BAD_REQUEST:400 */ 5 public static String ILLEGAL_ARGUMENT = "ILLEGAL_ARGUMENT"; 6 /** 7 * 错误码 8 */ 9 private String errorNo; 10 11 }
2.服务端得到Request,Response
通过 RPCContext.getRequest(),RPCContext.getResponse()得到HttpServletRequest,HttpServletResponse
3.客户端网络连接出错重试
<bean name="userWebService" class="com.duowan.common.rpc.client.RPCProxyFactoryBean"> <property name="serviceUrl" value="http://localhost:6060/rpc/UserWebService"/> <property name="serviceInterface" value="com.duowan.common.rpc.fortestinvoker.UserWebService" /> <!-- socket出错重试三次,间隔1秒,5秒,10秒 --> <property name="retryIntervalMills" value="1000,5000,10000"/> </bean>
4.客户端Timeout(超时)配置
<bean name="httpInvokerRequestExecutor" class="com.duowan.common.rpc.client.CommonsHttpInvokerRequestExecutor"> <!-- 每次调用超时配置,单位毫秒,默认10秒 --> <property name="readTimeout" value="1000"></property> <!-- 远程服务连接超时配置,单位毫秒,默认3秒 --> <property name="connectionTimeout" value="1000"></property> </bean> <bean name="userWebService" class="com.duowan.common.rpc.client.RPCProxyFactoryBean"> <property name="serviceUrl" value="http://localhost:6060/services/UserWebService"></property> <property name="serviceInterface" value="com.duowan.common.rpc.fortestinvoker.UserWebService" /> <property name="httpInvokerRequestExecutor" ref="httpInvokerRequestExecutor"></property> </bean>
5.直接返回结果,不增加包装类
通过URL增加参数 &__noWrapResult=true,来指明直接返回结果,
{resultObject}
而不返回
{result: {resultObject} }
6.设置使用其它传输协议: json,java,hessian
默认的传输协议是: json,还可以使用其它传输协议
<bean name="httpInvokerRequestExecutor" class="com.duowan.common.rpc.client.CommonsHttpInvokerRequestExecutor"> <!-- 使用java序列化,共支持: application/json,application/java,application/hessian --> <property name="contentType" value="application/java"></property> </bean> <bean name="userWebService" class="com.duowan.common.rpc.client.RPCProxyFactoryBean"> <property name="serviceUrl" value="http://localhost:6060/services/UserWebService"></property> <property name="serviceInterface" value="com.duowan.common.rpc.fortestinvoker.UserWebService" /> <property name="httpInvokerRequestExecutor" ref="httpInvokerRequestExecutor"></property> </bean>
7.开启http gzip压缩
可以通过nginx压缩现在的http返回结果,客户端跟服务端都不需要作任何修改。