dubbo

ubbo协议已经用的很多了,这里来稍微介绍一下http协议,官方对http协议的说明简直少的让人发指。哈哈

百度大部分都只是讲了http服务端的配置

那就先从服务端的配置说起

dubbo需要的jar包这里就不说明了,网上找些maven的pom就可以

web.xml配置servlet,注意url-pattern 是需要拦截哪些请求

  1. <servlet>  
  2.         <servlet-name>dubbo</servlet-name>  
  3.         <servlet-class>com.alibaba.dubbo.remoting.http.servlet.DispatcherServlet</servlet-class>  
  4.         <load-on-startup>1</load-on-startup>  
  5.     </servlet>  
  6.     <servlet-mapping>  
  7.         <servlet-name>dubbo</servlet-name>  
  8.         <url-pattern>/api/*</url-pattern>  
  9.     </servlet-mapping>  
接着配置dubbo配置文件

  1. <dubbo:application name="imp" ></dubbo:application>  
  2.     <!-- <dubbo:protocol name="hessian" contextpath="imp/api" port="${dubbo.hessian.port}" server="servlet" threadpool="cached" threads="5000" register="false"></dubbo:protocol> -->  
  3.     <dubbo:protocol name="dubbo" port="30883" />  
  4.     <dubbo:protocol name="http" port="8080" server="servlet" contextpath="imp/api/httpService"/>   
  5.     <dubbo:provider group="${dubbo.group}" />  
  6.     <dubbo:consumer check="false"  group="${dubbo.group}"/>  
  7.       
  8.     <!-- 使用zookeeper注册中心暴露发现服务地址 -->  
  9.     <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

  1. public class DispatcherServlet extends HttpServlet {  
  2.   
  3.     private static final long serialVersionUID = 5766349180380479888L;  
  4.       
  5.     private static DispatcherServlet INSTANCE;  
  6.   
  7.     private static final Map<Integer, HttpHandler> handlers = new ConcurrentHashMap<Integer, HttpHandler>();  
  8.   
  9.     public static void addHttpHandler(int port, HttpHandler processor) {  
  10.         handlers.put(port, processor);  
  11.     }  
  12.   
  13.     public static void removeHttpHandler(int port) {  
  14.         handlers.remove(port);  
  15.     }  
  16.       
  17.     public static DispatcherServlet getInstance() {  
  18.         return INSTANCE;  
  19.     }  
  20.       
  21.     public DispatcherServlet() {  
  22.         DispatcherServlet.INSTANCE = this;  
  23.     }  
  24.   
  25.     protected void service(HttpServletRequest request, HttpServletResponse response)   
  26.             throws ServletException, IOException {  
  27.         HttpHandler handler = handlers.get(request.getLocalPort());  
  28.         if( handler == null ) {// service not found.  
  29.             response.sendError(HttpServletResponse.SC_NOT_FOUND, "Service not found.");  
  30.         } else {  
  31.             handler.handle(request, response);  
  32.         }  
  33.     }  
  34.   
  35. }  

进入handler.handle(request, response);


handle有hession、http、webservice 这里我们只看http的

点击进入HttpProtocol 这个类

  1. private class InternalHandler implements HttpHandler {  
  2.          
  3.        public void handle(HttpServletRequest request, HttpServletResponse response)  
  4.                throws IOException, ServletException {  
  5.            String uri = request.getRequestURI();  
  6.            HttpInvokerServiceExporter skeleton = skeletonMap.get(uri);  
  7.            if (! request.getMethod().equalsIgnoreCase("POST")) {  
  8.                response.setStatus(500);  
  9.            } else {  
  10.                RpcContext.getContext().setRemoteAddress(request.getRemoteAddr(), request.getRemotePort());  
  11.                try {  
  12.                    skeleton.handleRequest(request, response);  
  13.                } catch (Throwable e) {  
  14.                    throw new ServletException(e);  
  15.                }  
  16.            }  
  17.        }  
  18.          
  19.    }  

同志们看到了吗,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 中这二个方法

  1. protected <T> Runnable doExport(final T impl, Class<T> type, URL url) throws RpcException {  
  2.         String addr = url.getIp() + ":" + url.getPort();  
  3.         HttpServer server = serverMap.get(addr);  
  4.         if (server == null) {  
  5.             server = httpBinder.bind(url, new InternalHandler());  
  6.             serverMap.put(addr, server);  
  7.         }  
  8.         final HttpInvokerServiceExporter httpServiceExporter = new HttpInvokerServiceExporter();  
  9.         httpServiceExporter.setServiceInterface(type);  
  10.         httpServiceExporter.setService(impl);  
  11.         try {  
  12.             httpServiceExporter.afterPropertiesSet();  
  13.         } catch (Exception e) {  
  14.             throw new RpcException(e.getMessage(), e);  
  15.         }  
  16.         final String path = url.getAbsolutePath();  
  17.         skeletonMap.put(path, httpServiceExporter);  
  18.         return new Runnable() {  
  19.             public void run() {  
  20.                 skeletonMap.remove(path);  
  21.             }  
  22.         };  
  23.     }  

httpServiceExporter设置的二个参数

Service实现类,一般引用其它bean

ServiceInterface服务类型

这样就达到了暴露服务


  1. protected <T> T doRefer(final Class<T> serviceType, final URL url) throws RpcException {  
  2.        final HttpInvokerProxyFactoryBean httpProxyFactoryBean = new HttpInvokerProxyFactoryBean();  
  3.        httpProxyFactoryBean.setServiceUrl(url.toIdentityString());  
  4.        httpProxyFactoryBean.setServiceInterface(serviceType);  
  5.        String client = url.getParameter(Constants.CLIENT_KEY);  
  6.        if (client == null || client.length() == 0 || "simple".equals(client)) {  
  7.         SimpleHttpInvokerRequestExecutor httpInvokerRequestExecutor = new SimpleHttpInvokerRequestExecutor() {  
  8.             protected void prepareConnection(HttpURLConnection con,  
  9.                     int contentLength) throws IOException {  
  10.                 super.prepareConnection(con, contentLength);  
  11.                 con.setReadTimeout(url.getParameter(Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT));  
  12.                 con.setConnectTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT));  
  13.             }  
  14.         };  
  15.         httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor);  
  16.        } else if ("commons".equals(client)) {  
  17.         CommonsHttpInvokerRequestExecutor httpInvokerRequestExecutor = new CommonsHttpInvokerRequestExecutor();  
  18.         httpInvokerRequestExecutor.setReadTimeout(url.getParameter(Constants.CONNECT_TIMEOUT_KEY, Constants.DEFAULT_CONNECT_TIMEOUT));  
  19.         httpProxyFactoryBean.setHttpInvokerRequestExecutor(httpInvokerRequestExecutor);  
  20.        } else if (client != null && client.length() > 0) {  
  21.         throw new IllegalStateException("Unsupported http protocol client " + client + ", only supported: simple, commons");  
  22.        }  
  23.        httpProxyFactoryBean.afterPropertiesSet();  
  24.        return (T) httpProxyFactoryBean.getObject();  
  25.    }  
ServiceUrl路径

ServiceInterface服务类型

这样,消费方在调用服务FactoryBean的getObject()的时候,获取到的代理对象就是httpProxyFactoryBean的对象


所以最后得出结论,dubbo的http协议,只是最后远程调用走的http,消费方通过服务调用还是需要类似dubbo协议的调用方式。如果需要传统http访问方式则需要看dubbox


不过有兴趣的可以看看当当的dubbox

http://dangdangdotcom.github.io/dubbox/rest.html

在Dubbo中开发REST风格的远程调用

Apache Dubbo 是一款高性能、轻量级的开源分布式 RPC(Remote Procedure Call)框架,最初由阿里巴巴团队开发并贡献给 Apache 基金会。它专注于服务间的远程调用以及服务治理能力,具备良好的可扩展性和灵活性。 ### 架构特点 Dubbo 提供了完整的面向接口代理的服务模型,并支持多种通信协议和序列化方式。其核心组件包括: - **Provider**:暴露服务的一方,负责提供具体的业务功能。 - **Consumer**:调用远程服务的一方,通常作为客户端发起请求。 - **Registry**:注册中心用于存储服务地址和其他元数据,帮助 Consumer 发现 Provider 实例。 - **Monitor**:监控模块收集运行时指标,便于性能分析和服务优化。 - **Protocol & Transport Layer**:定义网络传输层的行为,允许开发者自定义或者集成新的协议[^1]。 ### 使用场景 适用于需要高效处理大量并发请求的企业级应用,尤其是那些依赖于稳定可靠的服务间交互的应用程序。例如,在电商平台中,订单管理系统可以通过 Dubbo 来协调库存系统、支付网关等多个后端服务之间的协作。此外,当企业希望对其内部已有的私有协议进行封装以便更好地融入现代微服务体系时,也可以利用 Dubbo 的插件化设计来达成目标[^2]。 ### 官方文档与社区资源 官方文档位于[dubbo.apache.org](https://dubbo.apache.org),这里不仅包含了详细的API说明和技术指南,还提供了如何快速入门的最佳实践案例分享。除了基础教程外,《分布式服务治理框架Apache Dubbo的学习及应用实战》这本书籍深入探讨了许多高级主题,比如定制化的过滤器链路追踪机制等实用技巧[^3]。而对于想要对比不同微服务技术栈优劣的技术人员来说,《个人学习笔记 - 分布式RPC框架Apache Dubbo》这篇文章则给出了关于为何选择Dubbo而非其他流行方案如Spring Cloud的理由阐述[^4]。 ```java // 示例代码展示了一个简单的服务消费者配置 public class ServiceConsumer { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"consumer.xml"}); context.start(); DemoService demoService = (DemoService)context.getBean("demoService"); // 获取远程服务代理 String hello = demoService.sayHello("world"); // 执行远程方法调用 System.out.println(hello); // 输出结果 } } ``` 以上展示了创建一个基本的服务消费者的Java代码片段;实际部署过程中还需要相应的XML配置文件指定具体的服务参数设置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值