前言:今天给大家给大家讲解的是Dubbp的调用原理,以及一个demo测试向大家展示Dubbo的运行过程。在前面一文中,给大家讲到了---Dubbo之Zookeeper安装测试和Zookeeper集群的搭建 ,在其中已经给大家讲到了Zookeeper集群的搭建,今天我们也要用到该集群,如果没有安装的,请先行安装,再看下文!!
1.Dubbo原理
1.1 高性能Java RPC框架
Apache Dubbo 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。

1.2 Dubbo特性
- 面向接口代理的高性能RPC调用
- 服务自动注册与发现
- 运行期流量调度
- 智能负载均衡
- 高度可扩展能力
- 可视化的服务治理与运维
以上几点接来源于dubbo的官网:http://dubbo.apache.org/zh-cn/
1.3 Dubbo工作原理
1.3.1 Dubbo高可用测试
- 测试1:将后台提供者宕机一台,检查是否影响消费者调用。
不影响 注册中心实现心跳检测机制. 即使没有注册中心,又要有提供者就可以正常访问
- 测试2: 将zookeeper宕机一台,检查是否影响用户使用。
不影响 因为zk搭建了集群.可以实现高可用
- 测试3: 将zookeeper集群全部宕机,检查是否影响用户使用。
不影响. 因为消费者将zk注册中心的数据,已经保存到本地(消费者的内存中),所以不收影响
1.3.2 Dubbo通讯问题
核心:微服务通信一般都是靠RPC(统称)
dubbo中的RPC基于dubbo的协议规范

1.4 Dubbo调用原理
1.4.1 原理说明
- 需求:是否可以实现服务的自动发现和注册

图很丑,没有大神级的画得好看,将就着看吧。
图示解析:
- 当服务提供者启动时,会将服务数据保存到zk中。
- 当zk接收用户服务信息之后,会将数据保存到服务列表中。
- 当消费者启动时,先连接zk获取zk的服务列表。
- 之后缓存到本地,方便下次访问。
- 消费者接收用户的请求时,根据负载均衡策略,实现请求的发送,并且获取服务端的数据(RPC)。
- Zk实时的心跳检测,如果后台服务器宕机,则需要更新自己的服务列表,同时广播给全部的客户端。
1.5 Dubbo入门案例
1.5.0 导入数据库
CREATE DATABASE /*!32312 IF NOT EXISTS*/`jtdb` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `jtdb`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(40) DEFAULT NULL,
`age` int(11) DEFAULT NULL,
`sex` char(40) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `cc` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8;
/*Data for the table `user` */
insert into `user`(`id`,`name`,`age`,`sex`) values (1,'黑熊精',4000,'男'),(2,'鲤鱼精',5000,'男'),(3,'金角大王',3000,'男'),(4,'银角大王',4000,'男'),(5,'唐僧',30,'男'),(6,'悟空',501,'男'),(7,'白龙驴',2000,'男'),(8,'八戒',502,'男'),(9,'沙悟净',503,'男'),(11,'小乔',17,'女'),(12,'貂蝉',18,'女'),(16,'黄月英',18,'女'),(17,'孙尚香',18,'女'),(18,'甄姬c',20,'女'),(21,'孙尚香D',18,'女'),(22,'刘备',40,'男'),(23,'陆逊',33,'男'),(24,'陆逊',33,'男'),(25,'关羽',40,'男'),(27,'阿科',20,'女'),(31,'王昭君',19,'女'),(38,'貂蝉',18,'女'),(39,'西施',18,'女'),(40,'严真煌',16,'女'),(41,'白骨精',18,'女'),(43,'小乔',19,'男'),(44,'大乔',19,'女'),(46,'不知火舞',18,'女'),(49,'小兰兰',18,'男'),(50,'柳鹏林',18,'男'),(51,'妲己',18,'男'),(52,'如花',17,'男');
1.5.1 项目搭建
- 创建 dubbo-jt 为父类项目(Maven Project)
- 在dubbo-jt下,创建dubbo-jt-demo-consumer/interface/provider/provider2 四个子级项目(Maven Module)
- 在此之前你可以创建dubbo的工作空间


- 如果前三步做成,你将会看到

1.5.2 导入pom文件 -- 最后一个dependency就是dubbo的配置
dubbo-jt的pom文件
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<!--添加maven插件 -->
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
</properties>
<dependencies>
<!--springBoot动态的引入springMVC全部的配置 -->
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!--支持热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!--引入插件lombok 自动的set/get/构造方法插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--引入数据库驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--引入druid数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<!--spring整合mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.6</version>
</dependency>
<!--spring整合redis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
<!--springBoot整合JSP添加依赖 -->
<!--servlet依赖 注意与eureka整合时的问题 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!--jstl依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!--使jsp页面生效 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--添加httpClient jar包 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<!--引入dubbo配置 -->
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
</dependencies>
<modules>
<module>dobbo-jt-demo-interface</module>
<module>dubbo-jt-demo-provider</module>
<module>dubbo-jt-demo-consumer</module>
<module>dubbo-jt-demo-provider2</module>
</modules>
dubbo-jt-demo-consumer --编辑pom文件(消费者)
<parent>
<groupId>com.jt.dubbo</groupId>
<artifactId>dubbo-jt</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>dubbo-jt-demo-consumer</artifactId>
<dependencies>
<dependency>
<groupId>com.jt.dubbo</groupId>
<artifactId>dubbo-jt-demo-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
dubbo-jt-demo-provider/provider2 --编辑pom文件(提供者)
<parent>
<groupId>com.jt.dubbo</groupId>
<artifactId>dubbo-jt</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>dubbo-jt-demo-provider</artifactId>
<dependencies>
<dependency>
<groupId>com.jt.dubbo</groupId>
<artifactId>dubbo-jt-demo-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
1.5.3 编写intrface (第三方接口)
在com.jt.dubbo.pojo中,创建User实体类
@Data
@Accessors(chain=true)
@TableName
public class User implements Serializable{
//dubbo协议传输的对象必须序列化
private static final long serialVersionUID = 1L;
@TableId(type=IdType.AUTO)
private Integer id;
private String name;
private Integer age;
private String sex;
}
在com.jt.dubbo.service中创建UserService
public interface UserService {
//查询全部用户信息
List<User> findAll();
//导入数据库
@Transactional
void saveUser(User user);
}
1.5.4 编写consumer(消费者)
在com.jt下编写启动类SpringBoot_Run
//springBoot启动时排除数据源启动项
@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)
public class SpringBoot_Run {
public static void main(String[] args) {
SpringApplication.run(SpringBoot_Run.class, args);
}
}
在resources下编辑application.yml 文件
server:
port: 9001
dubbo:
scan:
basePackages: com.jt
application:
name: consumer-user #消费者名称
registry:
address: zookeeper://192.168.126.166:2181?backup=192.168.126.166:2182,192.168.126.166:2183
在com.jt.dubbo.controller下创建UserController类
@RestController
public class UserController {
@Reference(timeout=3000,check=true)
//@Autowired //从spring容器中进行注入
private UserService userService; //注入第三方管理的service
@RequestMapping("/findAll")
public List<User> findAll(){
return userService.findAll();
}
@RequestMapping("/saveUser/{name}/{age}/{sex}")
public String saveUser(User user) {
userService.saveUser(user);
return "用户入库成功!!!";
}
}
1.5.5 编写provider(提供者1)
启动类SpringBoot_Run
@SpringBootApplication
@MapperScan("com.jt.dubbo.mapper")
public class SpringBoot_Run {
public static void main(String[] args) {
SpringApplication.run(SpringBoot_Run.class, args);
}
}
application.yml文件编写
server:
port: 9000 #定义端口
spring:
datasource:
#引入druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
dubbo:
scan:
basePackages: com.jt #指定dubbo包路径
application:
name: provider-user #指定服务名称(必须指定)
registry:
address: zookeeper://192.168.126.166:2181?backup=192.168.126.166:2182,192.168.126.166:2183
protocol: #指定协议
name: dubbo #使用dubbo协议(tcp-ip) web-controller直接调用sso-service
port: 20880 #服务链接时的端口
mybatis-plus:
type-aliases-package: com.jt.dubbo.pojo #配置别名包路径
mapper-locations: classpath:/mybatis/mappers/*.xml #添加mapper映射文件
configuration:
map-underscore-to-camel-case: true #开启驼峰映射规则
在resources/mybatis/mappers下创建UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jt.dubbo.mapper.UserMapper">
</mapper>
在com.jt.dubbo.mapper下编写UserMapper接口(使用的是MybatisPlus)
public interface UserMapper extends BaseMapper<User>{
}
在com.jt.dubbo.service下创建UserServiceImpl类
@Service(timeout=3000) //3秒超时
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
System.out.println("我是第一个服务的提供者");
return userMapper.selectList(null);
}
@Override
public void saveUser(User user) {
userMapper.insert(user);
}
}
1.5.6 provider2 (提供者2)
与provider相比,
- 更改application.yml中的
server:port:9003 - 以及更改dubbo的端口号为20882因为每个服务都应该有自己独立的端口
- UserServiceImpl中的---
System.out.println("我是第二个服务提供者");
1.6 测试效果
1.6.0 开启zk集群

1.6.1 开启consumer/provider/provider2
1.6.2 搜索 localhost:9001/findAll 数据显示,表示查询成功

1.6.3 在后台显示provider/provider2均可被调用


1.6.4 将zk集群全部宕机 -- 后台会一直报如错误

1.6.5 即使所有集群被宕机,也不会影响消费者的使用
因为 消费者启动时已经将服务信息缓存到本地,故不会影响
亦或者有一个提供者宕机了,用户依然可以正常访问,且本地服务列表还会动态更新,只不过该程序将处于高位运行状态之下。

来源:oschina
链接:https://my.oschina.net/u/4115134/blog/3212254
