Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。 微服务使用最普遍的框架就是SpringCloud跟Dubbo。Dubbo比较专一于服务治理这块,而SpringCloud全家桶则提供了微服务的一整套解决方案html
Dubbo采用全Spring配置方式,透明化接入应用,对应用没有任何API侵入,不论是Provider仍是Consumer均可以经过Spring的配置文件进行配置,配置完以后,就能够像使用springbean同样进行服务暴露和调用了,彻底看不到dubboapi的存在。Dubbo基于Spring的Schema扩展进行加载。java
如今还能够经过 API 的方式进行调用。git
架构图github
调用关系说明:web
连通性:连通性说明他们之间都存在着关系,好比说Provider,Consumer和Registry三者之间都是长链接,而Provider,Consumer向Registry注册服务以及订阅服务的时间都得向Monitor汇报算法
健壮性:而健壮性说明具备稳定性,好比说注册中心对等集群中的任意一台宕掉后,将自动切换到另外一台。就算注册中心所有宕掉,服务者和消费者仍能够经过本地缓存进行通信。spring
伸缩性:伸缩性就是能够经过增长机器部署实例进行添加新的注册中心和服务提供者apache
升级性:文档中提到的对将来架构的设想,比起目前框架它的特色是能够实现自动部署服务的本地代理以及能够经过访问压力来自动增减服务提供者api
本demo中用的是Zookeeper 3.4.14版本,用哪一个版本都行,记得改下demo中的pom文件里的ZK依赖配置就能够。下载和安装步骤能够参考如下连接:http://www.javashuo.com/article/p-cweqhrkt-kx.html缓存
为何采用Zookeeper?
本demo中采用Zookeeper做为Dubbo的注册中心时,ZK是一个树型的目录服务,支持变动推送,能够做为集群的管理工具使用。能够集中管理配置文件。
(1)服务提供者在初始化启动时,会在Zookeeper下的Dubbo节点下的服务节点下的providers节点下的节点建立一个子节点并写入URL,路径相似为 /dubbo/servicename/providers/ ,该路径下的全部子节点均为服务提供者。此时这些子节点都为临时节点,由于临时节点的生命周期与客户端会话相关,因此一旦提供者所在的机器出现故障致使提供者没法提供服务,该临时节点就会自动从Zookeeper删除。
此时由于服务者,注册中心,消费者之间是长链接,注册中心能感知服务者宕机,会告知消费者。
而监控中心是Dubbo服务治理体系中重要的一部分,它须要知道全部的服务提供者和消费者的变化状况 。因此它在启动时会在服务节点上注册一个watcher来监听子节点变化,路径为 /dubbo/servicename/ ,因此它也能感知服务提供者的宕机。
(2)还有一个特性就是Zookeeper的节点结构设计(树形),它以服务名和类型,也就是 /dubbo/servicename/类型 做为节点路径,符合Dubbo订阅和通知的需求,保证了以服务为粒度的变动通知,通知范围易于控制。因此即便服务提供者和消费者频繁变动,对Zookeeper的性能也不会形成多大影响。
建立Maven项目project,而后在工程里面建立三大模块moudle,分别为: dubbo-api (公共服务接口) 、 dubbo-consumer(消费者,调用远程服务)、 dubbo-provider(提供远程服务)。
(1)其中须要在整个项目的pom.xml文件中添加相关依赖:这里须要注意dubbo的版本问题,下面会讲到,这里插个眼先。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.test</groupId> <artifactId>dubbo_demo</artifactId> <version>1.0-SNAPSHOT</version> <modules> <module>dubbo_consumer</module> <module>dubbo_provider</module> <module>dubbo_api</module> </modules> <packaging>pom</packaging> <name>dubbo_demo Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.4.RELEASE</version> </dependency> <!-- 添加 日志依赖包 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.24</version> </dependency> <!-- 添加 dubbo 依赖包 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.6.3</version> </dependency> <!-- 添加 zookeeper 相关依赖包 --> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.14</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.8.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.8.0</version> </dependency> <!-- 添加 zkclient 依赖包 --> <dependency> <groupId>com.github.sgroschupf</groupId> <artifactId>zkclient</artifactId> <version>0.1</version> </dependency> </dependencies> <build> <finalName>dubbo_demo</finalName> <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) --> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging --> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
(2) 建立dubbo_api moudle,在项目中定义服务接口:该接口需单独打包,在服务提供方和消费方共享 在dubbo-api中定义服务接口DemoService,以下:
package com.test; public interface DemoService { public String sayHello(String name); }
(3)建立dubbo_provider moudle,而后在dubbo_provider中实现上述接口。为何这里能实现跨moudle调用接口而且完成接口实现,由于在provider的pom.xml文件中添加了dubbo_api做为依赖,故能引入上述接口。如图
其中接口实现类DemoServiceImpl代码以下:
import com.test.DemoService; public class DemoServiceImpl implements DemoService { public String sayHello(String name) { return "hello"+name; } }
同时在此moudle下写一个启动测试类,便于后面启动provider:
import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; public class ProviderTest { public static void main(String[] args){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:dubbo-provider.xml"); applicationContext.start(); System.out.println("Dubbo provider start,启动服务提供.."); try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } } }
(4)建立dubbo_consumer moudle,而后在dubbo_consumer中写一个启动测试类,便于后面启动consumer调用provider提供的服务:
import com.test.DemoService; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.IOException; public class ConsumerTest { public static void main(String[] args){ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:dubbo-consumer.xml"); applicationContext.start(); DemoService demoService = (DemoService) applicationContext.getBean("ddemoService"); System.out.println(demoService.sayHello(" guy")); try { System.in.read(); } catch (IOException e) { e.printStackTrace(); } } }
(5)上述代码写好后,好像各个moudle看起来好像没有联系?你们都好奇就是Dubbo是怎么实现服务的发布和远程调用的吧。接下来是重点,进行provider和consumer的配置
a. 在dubbo_provider的resource中新建dubbo_provider.xml文件,实现dubbo中provider的配置:
首先完成应用配置,配置当前提供方应用名为dubbo_provider。
而后完成注册中心配置,将Zookeeper做为注册中心,设定其地址。
而后进行协议配置,用于配置提供服务的协议信息,协议只由provider指定,使用port="20880"做为服务提供的接口,供consumer调用。
最后进行服务配置,用于暴露一个服务接口,其绝对路径interface="com.test.DemoService",代号为ref="demoService"
这里还须要为接口实现类配置一个bean,以供在provider的启动测试类中调用bean中的方法。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 提供方应用信息,用于计算依赖关系 --> <dubbo:application name="dubbo_provider" /> <!-- 使用zookeeper注册中心暴露服务地址 --> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!-- 用dubbo协议在20880端口暴露服务 --> <dubbo:protocol name="dubbo" port="20880" /> <!-- 和本地bean同样实现服务 --> <bean id="demoService" class="DemoServiceImpl" /> <!-- 声明须要暴露的服务接口 --> <dubbo:service interface="com.test.DemoService" ref="demoService" /> </beans>
b. 在dubbo_consumer的resource中新建dubbo_consumer.xml文件,实现dubbo中consumer的配置。
首先完成应用配置,配置当前消费方应用名为dubbo_consumer;
而后完成完成注册中心配置,将Zookeeper做为注册中心,设定其地址。消费方向注册中心订阅本身所需的服务;
最后生成远程服务代理,调用到了绝对路径为interface="com.test.DemoService" 的接口,设定其代号为id="ddemoService",能够和本地bean同样使用ddemoService、
(这里可能你们有个问题,为何这里多了个d,由于为了和dubbo_provider.xml暴露的服务接口和bean作区别。说明消费方调用到此接口服务后,至关于本身的本地有了这个接口,因此接口名能够和provider的不同。至关于我在别人那里拿了一个苹果,在我这里我就能够不叫他苹果,我叫他梨也能够,由于这个东西是在我手上(本地),我怎么用本地都清楚,不须要外人(provider)清楚)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方同样 --> <dubbo:application name="dubbo_consumer" /> <!-- 使用zookeeper注册中心暴露发现服务地址 --> <dubbo:registry protocol="zookeeper" address="zookeeper://127.0.0.1:2181" /> <!-- 生成远程服务代理,能够和本地bean同样使用demoService --> <dubbo:reference id="ddemoService" interface="com.test.DemoService" /> </beans>
(6)项目结构以下,具体能够在文末下载本项目demo。
依次启动zookeeper(打开bin文件下的zkServer.cmd,而且不要关闭。若是闪退的会能够用cmd调用文件名打开)、运行dubbo-provider、运行dubbo-consumer得到测试结果以下。
本项目遇到了一个比较奇葩的问题找了我一天,每次在运行provider和consumer的时候都会出现下述问题。
问题:找不到Spring命名空间处理程序。
Offending resource: class path resource [dubbo-consumer.xml]; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://dubbo.apache.org/schema/dubbo]
Offending resource: class path resource [dubbo-consumer.xml]
就是下图红框的两个地址有问题,但是这两个地址都是能够打开的。
问题所在:最终发现以前有段时间dubbo被关闭了一段时间,那段时间dubbo的域名是code.alibabatech.com ,网上找到别人的案例里面配置的都是下面这种地址,结果发现这些地址都失效。按道理我如今程序里用最新的应该没错,为何还会报错了。又只能继续处处找bug。
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd ">
后来开始怀疑是否是我一开始用的版本比较旧(2.5.X);而后发现果真如此。问题在于: dubbo-config-spring-2.6.1.jar --> META-INF-->spring.handlers 中的配置仍是以前的域名 code.alibabatech.com , 可是这个域名已经不可用了,因此用dubbo旧版本的须要注意下这个问题(参考https://blog.csdn.net/huweijun_2012/article/details/80239803)
可是如今2.6.2以上都版本都不出现这个问题了,spring.handlers 中的配置仍是以前的域名 包含旧的和新的域名,至关于能够兼容。可是因为code.alibabatech.com 域名已经不可用,因此解决办法只能是在pom.xml文件中修改dubbo的版本,使用至少2.6.2以上版本就不会出现此问题。
本文demo下载地址:(个人git还没空弄,后续补上~)
连接: https://pan.baidu.com/s/1d4iPfCu21CKfaW_T8_QMFA 提取码: 74wn
本文参考:
http://dubbo.apache.org/zh-cn/docs/user/quick-start.html
http://www.javashuo.com/article/p-mluvmral-nn.html
http://www.javashuo.com/article/p-cweqhrkt-kx.html
https://blog.csdn.net/huweijun_2012/article/details/80239803