【Dubbo】入门案例
1、Dubbo简介
Dubbo的产生和网站应用的演进息息相关。网站应用经历了单一应用架构、垂直应用架构、分布式服务架构、流动计算架构,在很多博客中都有详细的介绍,这里就不再展开说明。
Dubbo的需求:
(1)管理服务URL,实现软负载均衡;
(2)自动梳理应用间的依赖关系;
(3)统计服务每天的调用量、响应时间,动态调整权重,反推服务总容量。
Dubbo官方网址:https://dubbo.apache.org/zh/docs/
2、Dubbo的架构
上图截取自官方。
角色说明:
container:服务运行的容器;
provider:服务提供方
consumer:服务消费方;
registry:注册中心
调用关系:
0-服务容器负责启动、加载、运行服务提供方
1-服务提供方在启动时向注册中心注册自己提供的服务
2-服务消费者在启动时向注册中心订阅服务
3-注册中心返回服务提供者的地址列表给消费者
4-服务消费者从地址列表中基于负载均衡算法,选择一台服务提供者进行调用
5-服务提供者和消费者定时发送累计调用次数和调用时间给监控中心。
3、入门案例
入门案例分两个,第一个是服务提供者和服务消费者直接连接,不通过注册中心;第二个是服务提供方向注册中心注册,服务消费者到注册中心获取服务地址列表
3.1、服务提供者和服务消费者直连
3.1.1、创建服务接口
创建一个服务接口,里面只有一个简单的sayHello方法用于演示。服务接口创建完成后通过maven打包install到本地仓库中,在服务提供者和服务消费者之间共享。
public interface ProviderService {
public String sayHello(String name);
}
3.1.2、服务提供方
(1)导入依赖:服务提供方所需依赖主要是dubbo、spring和刚才创建的服务接口的依赖。这里要注意dubbo和spring的版本,可能会出现不兼容的问题。本例中dubbo的版本是2.6.0,spring的版本是5.0.5.RELEASE
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>provider_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
(2)编写服务实现类
public class ProviderServiceImpl implements ProviderService {
@Override
public String sayHello(String s) {
System.out.println("provider实现类-------");
return "Hello,"+s;
}
}
(3)provider配置
因为这里不使用注册中心,所以registry的地址没有写。dubbo:service暴露了服务的接口,接口引用了实现类,所以消费方虽然只获取了服务接口,也能调用实现类的方法。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 -->
<dubbo:application name="provider"/>
<!-- 注册 协议和port -->
<dubbo:protocol name="dubbo" port="20881"></dubbo:protocol>
<dubbo:service interface="com.wxf.service.ProviderService" ref="providerService"/>
<bean id="providerService" class="com.wxf.service.impl.ProviderServiceImpl"></bean>
</beans>
(4)启动类
public class Start {
public static void main(String[] args) throws IOException {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(new String[] {"META-INF/spring/provider.xml"});
ac.start();
System.in.read();
}
}
3.1.3、消费方
(1)导入依赖:消费方的依赖和服务方的一样。
(2)consumer.xml
consumer通过服务方发布服务的地址获取服务。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<dubbo:application name="consume"/>
<dubbo:reference id="providerService"
interface="com.wxf.service.ProviderService"
url="dubbo://localhost:20881"/>
</beans>
(3)启动类
public class ConsumerStart {
public static void main(String[] args) {
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("consumer.xml");
ac.start();
ProviderService provider = (ProviderService) ac.getBean("providerService");
System.out.println(provider.sayHello("dubbo"));
}
}
结果:
这样就完成了一个简单的服务方和消费方直连的案例。
3.2、加上注册中心的案例
把上面的案例稍加修改:
(1)服务提供方:
在服务提供方的配置文件中加上接口地址:
<dubbo:registry address="zookeeper://localhost:2181"/>
(2)消费方
在消费方的配置文件中加上zookeeper的地址,并且把reference中的url去掉
<dubbo:registry address="zookeeper://localhost:2181"/>
<dubbo:reference id="providerService"
interface="com.wxf.service.ProviderService"
/>
服务提供方和消费方都要加上zookeeper和zkcli的依赖:
zookeeper的版本是3.4.7
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
(3)启动
先启动zookeeper的server端,再启动服务提供者,再启动消费者,就可以在zookeeper的client端看到结果啦
可以看到ProviderService已经注册了:
启动客户端,可以发现客户端的控制台可以打印出信息:
zookeeper上也可以看到消费方的信息
4、思考
我在做这个案例的时候一直有一个疑问,为什么不把服务提供者打成jar包通过maven导入依赖的方式给消费方使用。其实是因为现在做的项目还太简单,没办法体会大项目微服务架构会面临的问题。比如当服务提供者有很多个,打成jar包是很难实现负载均衡的。回到dubbo设计的初衷,要解决管理服务的url、实现负载均衡、自动推测依赖关系、自动计算什么时候需要加机器等等问题,这些都很难通过打成jar包实现。
还有一个问题也比较常见,就是dubbo和springcloud的区别。springcloud提供了服务注册与发现,服务消费,服务保护与熔断,网关,分布式调用追踪,分布式配置管理等一整套解决方案,集成了很多优秀的框架,功能齐全、强大。而dubbo有点像springcloud的子集,功能不是特别完善,很多需要自己配置,门槛较高。他俩一个很重要的区别就是通信方式,dubbo采用的RPC通信,springcloud采用的是http通信方式,至于这二者有什么不同,等我弄清楚了再另开一篇博客说明。
以上是dubbo简单的入门案例。如果有什么不对的地方,欢迎指正。