dubbo组成原理-http服务消费端如何调用
2017-05-11 15:55
393 查看
dubbo协议已经用的很多了,这里来稍微介绍一下http协议,官方对http协议的说明简直少的让人发指。哈哈
百度大部分都只是讲了http服务端的配置
那就先从服务端的配置说起
dubbo需要的jar包这里就不说明了,网上找些maven的pom就可以
web.xml配置servlet,注意url-pattern 是需要拦截哪些请求
因为dubbo支持多协议,所以这里配置了dubbo与http二种
http配置需要注意contextpath这个参数,引用一下官方说明
协议的上下文路径<dubbo:protocol contextpath="foo" />必须与servlet应用的上下文路径相同
什么看不懂?跑起来打个断点看看
用java模拟一个psot的http请求http://localhost:8080/imp/api/httpService/com.hellowin.imp.common.service.IDeviceService
服务端接收到http请求,因为/api/。所以会被DispatcherServlet拦截执行service
进入handler.handle(request, response);
handle有hession、http、webservice 这里我们只看http的
点击进入HttpProtocol 这个类
同志们看到了吗,skeletonMap.get(uri);。是不是很像springmvc中根据url定位handlermapping
所以http暴露服务的路径是contextpath +暴露接口类名称
最开始我以为可以模拟http请求调用dubbo接口,因为网上始终找不到demo,都是各种复制黏贴的内容,所以打算通过源码来研究一下是否可以通过模拟http请求来实现调用。
当跟进到HttpProtocol 中看到HttpInvokerServiceExporter 感觉不妙
HttpInvokerServiceExporter 是spring-web.jar包下的一个类,以下是介绍
Spring HTTP Invoker一种JAVA远程方法调用框架实现,原理与JDK的RMI基本一致,所以我们先跟其它JAVA远程方法调用实现做下简单比较。
RMI:使用JRMP协议(基于TCP/IP),不允许穿透防火墙,使用JAVA系列化方式,使用于任何JAVA应用之间相互调用。
Hessian:使用HTTP协议,允许穿透防火墙,使用自己的系列化方式,支持JAVA、C++、.Net等跨语言使用。
Burlap: 与Hessian相同,只是Hessian使用二进制传输,而Burlap使用XML格式传输(两个产品均属于caucho公司的开源产品)。
Spring HTTP Invoker: 使用HTTP协议,允许穿透防火墙,使用JAVA系列化方式,但仅限于Spring应用之间使用,即调用者与被调用者都必须是使用Spring框架的应用。
Spring一定希望大家尽量使用它的产品,但实际项目中我们还是要根据需求来决定选择哪个框架,下面我们来看看Spring HTTP Invoker的使用。
既然通过是HTTP请求调用,那么客户端肯定需要一个代理用于帮忙发送HTTP请求,帮忙做对象系列化和反系列化等,Spring框架中的HttpInvokerServiceExporter类处理这些杂事;而服务器端需要一个HTTP请求处理器,帮忙处理HTTP请求已经对象系列化和反系列化工作,Spring框架中的HttpInvokerServiceExporter类就是干这活的,对于Sun
JRE 6 的HTTP Server,Spring还提供了SimpleHttpInvokerServiceExporter类供选择。
网上有一些SimpleHttpInvokerServiceExporter的服务端和客户端配置说明,这里就不说明了
之前介绍dubbo说过,服务方就是doExport,消费方就是doRefer。继续看HttpProtocol 中这二个方法
httpServiceExporter设置的二个参数
Service实现类,一般引用其它bean
ServiceInterface服务类型
这样就达到了暴露服务
ServiceInterface[b]服务类型[/b]
[b]这样,消费方在调用服务FactoryBean的getObject()的时候,获取到的代理对象就是httpProxyFactoryBean的对象[/b]
所以最后得出结论,dubbo的http协议,只是最后远程调用走的http,消费方通过服务调用还是需要类似dubbo协议的调用方式。如果需要传统http访问方式则需要看dubbox
不过有兴趣的可以看看当当的dubbox
http://dangdangdotcom.github.io/dubbox/rest.html
百度大部分都只是讲了http服务端的配置
那就先从服务端的配置说起
dubbo需要的jar包这里就不说明了,网上找些maven的pom就可以
web.xml配置servlet,注意url-pattern 是需要拦截哪些请求
<servlet> <servlet-name>dubbo</servlet-name> <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dubbo</servlet-name> <url-pattern>/api/*</url-pattern> </servlet-mapping>接着配置dubbo配置文件
<dubbo:application name="imp" ></dubbo:application> <!-- <dubbo:protocol name="hessian" contextpath="imp/api" port="${dubbo.hessian.port}" server="servlet" threadpool="cached" threads="5000" register="false"></dubbo:protocol> --> <dubbo:protocol name="dubbo" port="30883" /> <dubbo:protocol name="http" port="8080" server="servlet" contextpath="imp/api/httpService"/> <dubbo:provider group="${dubbo.group}" /> <dubbo:consumer check="false" group="${dubbo.group}"/> <!-- 使用zookeeper注册中心暴露发现服务地址 --> <dubbo:registry protocol="zookeeper" address="${dubbo.zookeeper.address}" check="false" file="/home/epay/.dubbo/dubbo-registry-imp.cache" ></dubbo:registry>
因为dubbo支持多协议,所以这里配置了dubbo与http二种
http配置需要注意contextpath这个参数,引用一下官方说明
协议的上下文路径<dubbo:protocol contextpath="foo" />必须与servlet应用的上下文路径相同
什么看不懂?跑起来打个断点看看
用java模拟一个psot的http请求http://localhost:8080/imp/api/httpService/com.hellowin.imp.common.service.IDeviceService
服务端接收到http请求,因为/api/。所以会被DispatcherServlet拦截执行service
public class DispatcherServlet extends HttpServlet { private static final long serialVersionUID = 5766349180380479888L; private static DispatcherServlet INSTANCE; private static final Map<Integer, HttpHandler> handlers = new ConcurrentHashMap<Integer, HttpHandler>(); public static void addHttpHandler(int port, HttpHandler processor) { handlers.put(port, processor); } public static void removeHttpHandler(int port) { handlers.remove(port); } public static DispatcherServlet getInstance() { return INSTANCE; } public DispatcherServlet() { DispatcherServlet.INSTANCE = this; } protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpHandler handler = handlers.get(request.getLocalPort()); if( handler == null ) {// service not found. response.sendError(HttpServletResponse.SC_NOT_FOUND, "Service not found."); } else { handler.handle(request, response); } } }
进入handler.handle(request, response);
handle有hession、http、webservice 这里我们只看http的
点击进入HttpProtocol 这个类
private class InternalHandler implements HttpHandler { public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { String uri = request.getRequestURI(); HttpInvokerServiceExporter skeleton = skeletonMap.get(uri); if (! request.getMethod().equalsIgnoreCase("POST")) { response.setStatus(500); } else { RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort()); try { skeleton.handleRequest(request, response); } catch (Throwable e) { throw new ServletException(e); } } } }
同志们看到了吗,skeletonMap.get(uri);。是不是很像springmvc中根据url定位handlermapping
所以http暴露服务的路径是contextpath +暴露接口类名称
最开始我以为可以模拟http请求调用dubbo接口,因为网上始终找不到demo,都是各种复制黏贴的内容,所以打算通过源码来研究一下是否可以通过模拟http请求来实现调用。
当跟进到HttpProtocol 中看到HttpInvokerServiceExporter 感觉不妙
HttpInvokerServiceExporter 是spring-web.jar包下的一个类,以下是介绍
Spring HTTP Invoker一种JAVA远程方法调用框架实现,原理与JDK的RMI基本一致,所以我们先跟其它JAVA远程方法调用实现做下简单比较。
RMI:使用JRMP协议(基于TCP/IP),不允许穿透防火墙,使用JAVA系列化方式,使用于任何JAVA应用之间相互调用。
Hessian:使用HTTP协议,允许穿透防火墙,使用自己的系列化方式,支持JAVA、C++、.Net等跨语言使用。
Burlap: 与Hessian相同,只是Hessian使用二进制传输,而Burlap使用XML格式传输(两个产品均属于caucho公司的开源产品)。
Spring HTTP Invoker: 使用HTTP协议,允许穿透防火墙,使用JAVA系列化方式,但仅限于Spring应用之间使用,即调用者与被调用者都必须是使用Spring框架的应用。
Spring一定希望大家尽量使用它的产品,但实际项目中我们还是要根据需求来决定选择哪个框架,下面我们来看看Spring HTTP Invoker的使用。
既然通过是HTTP请求调用,那么客户端肯定需要一个代理用于帮忙发送HTTP请求,帮忙做对象系列化和反系列化等,Spring框架中的HttpInvokerServiceExporter类处理这些杂事;而服务器端需要一个HTTP请求处理器,帮忙处理HTTP请求已经对象系列化和反系列化工作,Spring框架中的HttpInvokerServiceExporter类就是干这活的,对于Sun
JRE 6 的HTTP Server,Spring还提供了SimpleHttpInvokerServiceExporter类供选择。
网上有一些SimpleHttpInvokerServiceExporter的服务端和客户端配置说明,这里就不说明了
之前介绍dubbo说过,服务方就是doExport,消费方就是doRefer。继续看HttpProtocol 中这二个方法
protected <T> Runnable doExport(final T impl, Class<T> type, URL url) throws RpcException { String addr = url.getIp() + ":" + url.getPort(); HttpServer server = serverMap.get(addr); if (server == null) { server = httpBinder.bind(url, new InternalHandler()); serverMap.put(addr, server); } final HttpInvokerServiceExporter httpServiceExporter = new HttpInvokerServiceExporter(); httpServiceExporter.setServiceInterface(type); httpServiceExporter.setService(impl); try { httpServiceExporter.afterPropertiesSet(); } catch (Exception e) { throw new RpcException(e.getMessage(), e); } final String path = url.getAbsolutePath(); skeletonMap.put(path, httpServiceExporter); return new Runnable() { public void run() { skeletonMap.remove(path); } }; }
httpServiceExporter设置的二个参数
Service实现类,一般引用其它bean
ServiceInterface服务类型
这样就达到了暴露服务
protected <T> T doRefer(final Class<T> serviceType, final URL url) throws RpcException { final HttpInvokerProxyFactoryBean httpProxyFactoryBean = new HttpInvokerProxyFactoryBean(); httpProxyFactoryBean.setServiceUrl(url.toIdentityString()); httpProxyFactoryBean.setServiceInterface(serviceType); String client = url.getParameter(Constants.CLIENT_KEY); if (client == null || client.length() == 0 || "simple".equals(client)) { SimpleHttpInvokerRequestExecutor httpInvokerRequestExecutor = new SimpleHttpInvokerRequestExecutor() { protected void prepareConnection(HttpURLConnection con, int contentLength) throws IOException { super.prepareConnection(con, contentLength); con.setReadTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT)); con.setConnectTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT)); } }; httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor); } else if ("commons".equals(client)) { CommonsHttpInvokerRequestExecutor httpInvokerRequestExecutor = new CommonsHttpInvokerRequestExecutor(); httpInvokerRequestExecutor.setReadTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT)); httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor); } else if (client != null && client.length() > 0) { throw new IllegalStateException("Unsupported http protocol client " + client + ", only supported: simple, commons"); } httpProxyFactoryBean.afterPropertiesSet(); return (T) httpProxyFactoryBean.getObject(); }ServiceUrl路径
ServiceInterface[b]服务类型[/b]
[b]这样,消费方在调用服务FactoryBean的getObject()的时候,获取到的代理对象就是httpProxyFactoryBean的对象[/b]
所以最后得出结论,dubbo的http协议,只是最后远程调用走的http,消费方通过服务调用还是需要类似dubbo协议的调用方式。如果需要传统http访问方式则需要看dubbox
不过有兴趣的可以看看当当的dubbox
http://dangdangdotcom.github.io/dubbox/rest.html
在Dubbo中开发REST风格的远程调用
相关文章推荐
- dubbo组成原理-service服务调用
- Dubbo剖析-服务消费端泛化调用
- dubbo泛化调用 http接口 随意调用dubbo服务
- dubbo组成原理-service服务暴露
- Dubbo远程调用服务框架原理与示例
- Dubbo远程调用服务框架原理与示例
- 如何调用他人的远程服务---RPC原理
- 18. Dubbo原理解析-服务调用
- Dubbo远程调用服务框架原理与示例
- Dubbo 服务调用原理浅析
- 既然有http 请求,为什么还要用rpc(dubbo接口)调用?
- 微服务 Dubbo + Zookeeper 原理解析
- 实现jquery.ajax及原生的XMLHttpRequest跨域调用WCF服务的方法
- [ZooKeeper.net] 1 模仿dubbo实现一个简要的http服务的注册 基于webapi
- 【转载】WCF热门问题编程示例(4):WCF客户端如何异步调用WCF服务?
- alibaba远程调用框架dubbo原理
- 使用Spring Cloud Feign作为HTTP客户端调用远程HTTP服务
- dubbox 发布rest服务调用过程记录
- dubbo 服务的调用堆栈-- 学习dubbo启动后执行逻辑和代码
- 如何用javascript api for arcgis调用有参数的GP服务