一、背景
上一篇记录了下SpringCloud使用Eureka作为服务注册中心的简单示例,文末并未提及使用过程中的感受以及总结,在此先做个小结,主要有以下两点:
- 整体环境配置简单,只需考虑依赖和application.yml中的少许配置
- Eureka自带服务注册后台,查看服务注册启动情况更方便
对,是的,就这两点。至于SpringCloud之后的ribbon实现负载均衡、feign声明式服务调用、hystrix服务熔断、zuul…emmmm…我们有缘再见!
所以对比着Dubbo和SpirngCloud,今天使用Multicast作为服务发现与注册中心做了如下的示例。
二、Dubbo、Multicast介绍
略。本文只做简单的环境搭建示例。
不过多提一句关于dubbo的,dubbo官网那张架构图,建议没事儿多在纸上画画,理解的同时也要记牢了,面试要问的。如下:
至于Multicast注册中心,dubbo官网并未做详细介绍,也可以了解下。对比着单播、广播可能更好理解组播这种通讯方式。
三、框架版本选择
dubbo官网给出的示例参考,单纯的使用Spirng的ClassPathXmlApplicationContext加载的dubbo.xml配置,然后从IOC容器获取的对象实例进行调用。所以这里只给出该demo中使用的dubbo版本:
- dubbo - 2.7.0
但是,如果你想使用Springboot,这边建议参考dubbo-spring-boot-starter
三、环境搭建
工程结构:
1. 创建主工程gkd-dubbo-multicast-demo
引入依赖:
<properties>
<java.version>1.8</java.version>
<dubbo.version>2.7.0</dubbo.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-multicast</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-zookeeper</artifactId>
<version>${dubbo.version}</version>
</dependency>
</dependencies>
2. 分别创建provider和consumer两个子module
gkd-dubbo-multicast-provider
resource目录下创建spring/dubbo-provider.xml,并添加配置:
<?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-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 提供方应用信息,用于计算依赖关系 -->
<dubbo:application name="demo-provider"/>
<!-- 使用multicast广播注册中心暴露服务地址 -->
<dubbo:registry address="multicast://224.5.6.7:1234"/>
<!-- 用dubbo协议在20880端口暴露服务 -->
<dubbo:protocol name="dubbo" port="20880"/>
<!-- 声明需要暴露的服务接口 -->
<bean id="demoService" class="com.gkd.multicast.service.impl.DemoServiceImpl"/>
<!-- 和本地bean一样实现服务 -->
<dubbo:service interface="com.gkd.multicast.service.DemoService" ref="demoService"/>
</beans>
注意注册中心暴露的服务地址<dubbo:registry address=“multicast://224.5.6.7:1234”/>
编写服务DemoService:
/**
* 定义服务接口
*/
public interface DemoService {
String sayHello(String name);
}
以及DemoService的实现:
/**
* 在服务提供方实现接口
*/
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "Hello " + name;
}
}
最后服务启动类:
public class App {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-provider.xml");
context.start();
System.in.read();
}
}
gkd-dubbo-multicast-consumer
引入provider依赖:
<dependencies>
<dependency>
<groupId>com.gkd</groupId>
<artifactId>gkd-dubbo-multicast-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
同样resource目录下创建spring/dubbo-consumer.xml,并添加配置:
<?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-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
<!-- 消费方应用名,用于计算依赖关系,不是匹配条件,不要与提供方一样 -->
<dubbo:application name="demo-consumer"/>
<!-- 使用multicast广播注册中心暴露发现服务地址 -->
<!-- unicast=false 并没有配置也可以 -->
<dubbo:registry address="multicast://224.5.6.7:1234"/>
<!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
<dubbo:reference id="demoService" check="false" interface="com.gkd.multicast.service.DemoService"/>
</beans>
编写启动类并测试调用:
public class App {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-consumer.xml");
context.start();
DemoService demoService = (DemoService) context.getBean("demoService"); // 获取远程服务代理
String hello = demoService.sayHello("world"); // 执行远程方法
System.out.println(hello); // 显示调用结果
}
}
3. 启动provider服务,再启动consumer服务,调用结果:
Hello world
4. 源码地址:https://github.com/nidagewcc/gkd-spring-learning
示例我写了两种实现方式,区别不大:
- 一种是本文描述的通过spring的ClassPathXmlApplicationContext加载dubbo配置实现
- 另一种是基于dubbo-spring-boot-starter实现
四、遇到的问题
- dubbo官网提到“当服务者和消费者运行在同一台机器上,消费者同样需要声明unicast=false,否则消费者无法收到消息,导致No provider available for the service异常”,我在本机并没有配置,并没有导致异常,原因未知;
- “dubbo 2.5.8 新版本增加了 QOS 模块,提供了新的 telnet 命令支持”。我理解的是:
- 这个版本之后都需要配置dubbo.properties,并添加属性dubbo.application.qos.port=33333,不然会抛出异常
- provider和consumer服务设置的QOS端口要不一样;
- 该在线运维命令默认是开启的,如果要关闭请参考:http://dubbo.apache.org/zh-cn/docs/user/references/qos.html
- 在启动consumer服务调用provider的服务是,偶尔会出现异常:message can not send, because channel is closed。我个人是通过修改注册中心暴露的服务地址解决的。
五、总结
dubbo官网的参考也是比较重点和概括的,即使这么简单粗糙的demo中间过程也会踩到很多坑,所以多了解原理,多看源码是有必要的。
前作
以上。