Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务,要么是消费方消费服务,所以基于这一点可以抽象出服务提供方(Provider)和服务消费方(Consumer)两个角色。
Dubbo 的RPC 调用流程主要涉及到4个模块:
1、Registry:服务注册,我们一般会采取Zookeeper 作为我们的注册中心
2、Provider:服务提供者(生产者),提供具体的服务实现
3、Consumer:消费者,从注册中心中订阅服务
4、Monitor:监控中心,RPC调用次数和调用时间监控
从上图中我们可以看出RPC 服务调用的过程主要为:
1、生产者发布服务到服务注册中心
2、消费者在服务注册中心中订阅服务
3、消费者调用已注册的服务
1、IDEA下将SpringBoot与dubbo整合
项目结构图
- common: 通用模块
- provider: 服务提供者
- consumer: 服务调用者
## 最外部springboot-dubbo的pom.xml配置文件如下:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lcxu</groupId>
<artifactId>springboot-dubbo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-dubbo</name>
<description>Demo project for Spring Boot-Dubbo</description>
<packaging>pom</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<modules>
<module>common</module>
<module>provider</module>
<module>consumer</module>
</modules>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--dubbo-springBoot依赖-->
<dependency>
<groupId>com.alibaba.spring.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>1.0.1</version>
</dependency>
<!--zookeeper依赖-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.11</version>
</dependency>
<!--
1)zookeeper原生API使用中,经常会遇到session expire这类异常,异常发生后需要进行重新连接,重新建立session,会比较麻烦
2)zookeeper的watcher机制是一次性的,如果你想订阅节点的状态变化、子节点变化等,每次在处理完变化事件之后,需要重新注册watcher。可想而知这是一件令人绝望的事情。这个特性使得在处理事件和重新加上watcher这段时间发生的节点变化将无法被感知。
3)zookeeper的API接口中,节点数据默认为二进制byte数组,如果想直接保存对象类型的数据,需要相关的序列化工作。
以上问题,zkClient可以很好的解决。
-->
<dependency>
<groupId>com.101tec</groupId>
<artifactId>zkclient</artifactId>
<version>0.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
</project>
公共pom主要引入了: SpringBoot依赖,dubbo-springBoot依赖,zookeeper依赖,zkClient依赖等。
1、provider模块
-
项目代码结构:
-
pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lcxu</groupId>
<artifactId>springboot-dubbo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provider</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.lcxu</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
</project>
- application.yml
server:
port: 8081
spring:
dubbo:
appname: provider
registry: zookeeper://127.0.0.1:2181
protocol: dubbo
port: 20880
- ProviderApplication
package com.example.provider;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo //启动dubbo服务,它整合了 @EnableDubboConfig 和 @DubboComponentScan
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
- BookServiceImpl
package com.example.provider.service.impl;
import com.lcxu.common.api.provider.IBookServiceApi;
import org.springframework.stereotype.Service;
@Service
@com.alibaba.dubbo.config.annotation.Service
public class BookServiceImpl implements IBookServiceApi {
@Override
public String sayHello() {
return "hello, dubbo!这是一个简单的dubbo-demo!";
}
}
Provider模块代码就这么多。
2、Consumer模块
-
项目代码结构
-
pom.xml文件
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lcxu</groupId>
<artifactId>springboot-dubbo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.lcxu</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
</project>
- application.yml
server:
port: 8082
spring:
dubbo:
appname: provider
registry: zookeeper://127.0.0.1:2181
protocol: dubbo
port: 20880
- ConsumerApplication
package com.example.consumer;
import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import com.alibaba.dubbo.spring.boot.annotation.EnableDubboConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
- BookController
package com.example.consumer.controller;
import com.alibaba.dubbo.config.annotation.Reference;
import com.lcxu.common.api.provider.IBookServiceApi;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/book")
public class BookController {
@Reference
private IBookServiceApi bookService;
@GetMapping("/book")
private String getBook() {
return this.bookService.sayHello();
}
}
调用provider模块定义的service的时候,必须要加入@Reference注解
@Reference是dubbo的注解,也是注入,他一般注入的是分布式的远程服务的对象,需要dubbo配置使用。
3、common模块
common只是一个基础包,可以放一些接口,或者工具类,一些bean等。
- 项目结构图
- pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.lcxu</groupId>
<artifactId>common</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>common</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.4.5</version>
</plugin>
</plugins>
</build>
</project>
- IBookServiceApi
只定义了一个公共接口
package com.lcxu.common.api.provider;
public interface IBookServiceApi {
String sayHello();
}
至此,代码模块编写完成,但是目前还不能运行,因为还没有启动zookeeper。
2、zookeeper的安装,windows为例
1、下载zookeeper
下载地址:
https://zookeeper.apache.org/releases.html
2、解压
3、复制zoo_simple.cfg,重命名为zoo.cfg
根据实际情况修改下面配置
4、启动zookeeper
zookeeper命令,参照下面链接
zookeeper之 zkServer.sh命令、zkCli.sh命令、四字命令
cnblogs.com/andy6/p/7674028.html
启动zookeeper后,然后启动provider与consumer模块,再浏览器输入http://localhost:8082/book/book,即可实现模块的远程调用。
3、zookeeper可视化工具 zkui
1、下载zkui源码
源码地址:https://github.com/DeemOpen/zkui.git
2、编译
mvn clean
mvn install
编译成功,此时生成两个jar包,zkui-2.0-SNAPSHOT.jar和zkui-2.0-SNAPSHOT-jar-with-dependencies.jar,使用的是第二个jar包
3、修改配置文件
zkui运行生成的jar包,可以直接运行,在运行该文件之前,我们还需要修改zkui的配置文件config.cfg,config.cfg 文件中配置了zkui需要连接的zookeeper集群的IP地址和端口,访问UI的用户名和密码,以及zkui监听的端口号
4、启动程序
java -jar zkui-2.0-SNAPSHOT-jar-with-dependencies.jar
注意,需要将config.cfg复制到jar包的同一层目录去,不然启动会报错
5、访问页面,输入配置文件里的用户名密码
6、登录zkui ,选择导航“Host” 出现错误提示:KeeperErrorCode = NoNode for /appconfig/hosts 如下所示:
解决方案:
- 启动zkcli.cmd客户端,然后执行下面命令即可。
- 刷新,正常
至此,完成!
项目代码地址:https://gitee.com/lcxu/springboot-dubbo.git