分享自己在Java方面的所思所想,希望你看完之后能有更多更深入的了解
本人微信公众号(jwfy的学习分享),欢迎关注~
本学习笔记主要是介绍了dubbo的基础内容,简单说明了dubbo、rpc、soa、zk等概念,并没有直接贴出dubbo的组件调用图等内容,而是利用实际的代码介绍dubbo的服务提供方以及调用方的配置,对dubbo有一个感性的认识并通过dubbo-admin以及telnet查看dubbo的运行数据,后续会深入学习和分析dubbo spi以及暴露服务等等源码。
目录
Dubbo 介绍和使用 学习
1、前言
1.1、Dubbo 简介
1.2、RPC 简介
1.3、SOA 简介
1.4、Zookeeper 简介&安装
2、Dubbo 服务提供方
3、Dubbo 服务调用方
4、参考链接
1、前言
1.1、Dubbo 简介
Dubbo是由阿里巴巴基于java开发的一个RPC框架,经历过了长时间的停止维护后又重新开始维护,现在(2018年04月17日)已经划入了Apache孵化项目中,github地址:https://github.com/apache/incubator-dubbo,在国内属于一个应用广泛的RPC框架,接下来就一起来学习Dubbo是如何使用的,其原理又是如何。
TODO 提个问题那么Dubbo和Spring Cloud又有什么同异呢?
1.2、RPC 简介
RPC全称Remote Procedure Call,中文名叫远程过程调用,通过网络利用TCP或者UDP协议实现的不同机器之间的数据传输协议,A机器想调取B机器提供的服务,A机器拼接好自身请求的参数之后由RPC框架包装成为特定格式的数字,序列化后后通过网络发送到B机器上,B机器的RPC框架反解析出参数数据后去invoke调用自身机器的服务,最后按照原路返回到A机器上。
RPC是C/S模式,而且屏蔽了传输层和应用层,再基于特定的协议,使得用户只需要关注自身的业务即可。
1.3、SOA 简介
SOA全称Service-Oriented Architecture,中文名叫面向服务编程,另一个常用的名称是服务发现。业务繁多而且复杂就需要有一种统一的管理服务的机制,在分布式架构中,新加入的机器或者宕掉的机器后系统如何自动调整,一方面使得流量分发均衡,另一方面能够及时发现出现异常的服务;控制服务与服务的调用关系等,确保服务合理正常的运行,例如zookeeper可以统一管理各机器以及机器上的服务运行情况。
在我们介绍的dubbo也会使用zookeeper作为其服务注册中心
1.4、Zookeeper 简介&安装
zookeeper是为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
进入到http://mirrors.hust.edu.cn/apache/zookeeper/页面选择一个合适的版本,进入下载其tar.gz包,随便解压到一个本地目录,如下图
进入到conf文件夹,可以看到zoo_sample.cfg文件,直接cp一个名字为zoo.cfg的文件,可以把内容修改为如下内容
$ cat zoo.cfg tickTime=2000 dataDir=../data // 工作路径,表示为conf的上一级目录的data文件夹 dataLogDir=../logs // 日志的路径 clientPort=2182 // zk启动的端口
现在就可以启动zk了,进入到bin目录,Windows环境选择zkServer.cmd,Unix类环境选择zkServer.sh
$ ./zkServer.sh JMX enabled by default Using config: ./../conf/zoo.cfg Usage: ./zkServer.sh {start|start-foreground|stop|restart|status|upgrade|print-cmd}
如上述执行结果,很明显已经确实加载了之前配置的zoo.cfg文件,但是需要加上启动参数,其中有{start|start-foreground|stop|restart|status|upgrade|print-cmd}
- start-foreground 前台启动,可以看到实时日志
- start 后台启动
在这遇到一个,当前台启动之后,执行stop命令时,会提示没有发现对应的服务pid,可是如果以start方式启动,就可以正常使用stop关闭zk服务
zk服务已经正常启动了,如下图,1896端口的服务就是zk启动的java进程服务
2、Dubbo 服务提供方
整个的文件目录结构
spring-product.xml
<context:property-placeholder location="pro.properties" /> <!-- 消费方应用名 --> <dubbo:application name="${dubbo.application.name}" owner="${dubbo.application.owner}" /> <dubbo:provider loadbalance="random" default="true"/> <dubbo:registry protocol="zookeeper" address="${dubbo.zk.servers}" client="zkclient" group="${dubbo.zk.group}"/> <dubbo:protocol name="${dubbo.application.protocol.name}" port="${dubbo.application.protocol.port}"/> <!--<dubbo:monitor address="${dubbo.monitor.address}" />--> <dubbo:consumer check="false" /> <bean class="com.jwfy.dubbo.product.ProductServiceImpl" id="productService" /> <!-- 基础的bean 配置--> <dubbo:service interface="com.jwfy.dubbo.product.ProductService" ref="productService" /> <!-- dubbo 对外暴露的接口,映射到的实体bean是productService-->
pro.properties
# dubbo dubbo.application.name=dubbo-demo dubbo.application.owner=jwfy dubbo.application.protocol.name=dubbo dubbo.application.protocol.port=20880 # dubbo.monitor.address=dubbo://127.0.0.1:20888 dubbo.zk.servers=127.0.0.1:2182 dubbo.zk.group=dubbo-demo
dubbo的相关配置,包含了使用的协议以及端口还有zk的配置情况,这里就使用了2182端口,到时候就会连上上文启动的zk服务
ProductService 接口
public interface ProductService { void print(); String getStr(); }
dubbo对外暴露的时候都是通过动态代理反射的,必须存在相关接口
ProductServiceImpl 实现类
public class ProductServiceImpl implements ProductService { public void print() { System.out.println("print"); } public String getStr() { return "Hello World Product"; } }
ProductBootstrap 启动类
public class ProductBootstrap { /** * 其实这个函数是用硬编码的形式代替xml配置,xml配置最后都会变成如下的数据以及参数进行处理 */ public static void runProduct(){ ProductService demo = new ProductServiceImpl(); ApplicationConfig config=new ApplicationConfig("simple-spring-dubbo"); RegistryConfig reg=new RegistryConfig("127.0.0.1:2182"); reg.setProtocol("zookeeper"); ProtocolConfig protocol = new ProtocolConfig(); protocol.setName("dubbo"); protocol.setPort(20880); ServiceConfig<ProductService> service=new ServiceConfig<ProductService>(); service.setApplication(config); service.setRegistry(reg); service.setProtocol(protocol); service.setInterface(ProductService.class); service.setRef(demo); service.setVersion("1.0"); service.export(); // export是最关键的函数,对外暴露服务 // 包括了向zk注册以及启动netty服务等待接受调用 try { Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } } public static void runDubboProduct(){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext( new String[]{"spring-product.xml"}); while (true){ // 为了让服务不会自己终止,加个死循环 } } public static void main(String[] args){ //runProduct(); runDubboProduct(); } }
如下图dubbo-admin显示的数据,服务提供方已经正常启动,同时可以看到该服务的具体情况
可以通过Telnet查看当前机器上dubbo服务提供方的一些数据,当线上服务提供方添加了新的接口就可以通过该方法确认
3、Dubbo 服务调用方
调用方文件目录结构
spring-consume.xml 文件
<context:property-placeholder location="application.properties" /> <!-- 消费方应用名 --> <dubbo:application name="${dubbo.application.name}" owner="${dubbo.application.owner}" /> <dubbo:provider loadbalance="random" default="true"/> <dubbo:registry protocol="zookeeper" address="${dubbo.zk.servers}" client="zkclient" group="${dubbo.zk.group}"/> <dubbo:protocol name="${dubbo.application.protocol.name}" port="${dubbo.application.protocol.port}"/> <!--<dubbo:monitor address="${dubbo.monitor.address}" />--> <dubbo:consumer check="false" /> <dubbo:reference interface="com.jwfy.dubbo.product.ProductService" id="productService" />
application.proerties 文件
# dubbo dubbo.application.name=dubbo-consume dubbo.application.owner=jwfy dubbo.application.protocol.name=dubbo dubbo.application.protocol.port=20880 dubbo.monitor.address=dubbo://127.0.0.1:20888 dubbo.zk.servers=127.0.0.1:2182 dubbo.zk.group=dubbo-consumer-demo public class ConsumeBootstrap { private static final Logger logger = LoggerFactory.getLogger(ConsumeBootstrap.class); public static void runDubboConsume(){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext( new String[]{ "spring-consume.xml" }); ProductService productService = (ProductService)applicationContext.getBean("productService"); System.out.println(productService.getStr()); while (true){ } } public static void main(String[] args){ runDubboConsume(); } }
直接启动,显示连接拒绝错误
Exception in thread "main" com.alibaba.dubbo.rpc.RpcException: Forbid consumer 192.168.10.123 access service com.jwfy.dubbo.product.ProductService from registry 127.0.0.1:2182 use dubbo version 2.5.3, Please check registry access list (whitelist/blacklist). at com.alibaba.dubbo.registry.integration.RegistryDirectory.doList(RegistryDirectory.java:579) at com.alibaba.dubbo.rpc.cluster.directory.AbstractDirectory.list(AbstractDirectory.java:73) at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.list(AbstractClusterInvoker.java:260) at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:219) at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72) at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52) at com.alibaba.dubbo.common.bytecode.proxy0.getStr(proxy0.java) at com.jwfy.dubbo.consume.ConsumeBootstrap.runDubboConsume(ConsumeBootstrap.java:22) at com.jwfy.dubbo.consume.ConsumeBootstrap.main(ConsumeBootstrap.java:30)
拒绝链接到远程服务,这时候需要核对服务提供方以及服务调用方的配置是否不同
经过观察发现是服务调用方的zk组写错了,调用方在使用不存在的zk注册的时候,会被禁止掉,从而提示该错误
把application.proerties 中的dubbo.zk.group=dubbo-consumer-demo修改为dubbo.zk.group=dubbo-demo,再启动,就恢复正常了,再看看dubbo-admin的显示
原创推荐
「系列教程」手写RPC框架(1),看看100个线程同时调用情况如何