一、本章内容
1.1 主要内容
二、初识Dubbo
2.1 Dubbo框架:微服务之间,的高性能的RPC通信
官网:
用一句话概括,告诉别人这是什么。很重要。
Dubbo核心定义:微服务之间,的高性能的RPC通信。
历史:
2.2 RPC:远程调用
Dubbo框架,正是一款RPC理念的框架。当然,也有其他的RPC理念的框架:
2.3 HTTP vs RPC
2.4 Dubbo的工作原理(图)
5个角色
工作原理的图示:
其中:
init
----------- 初始化sync
----------- 同步调用( 后顺序,排队)-------------- same,只能走同一条路async
--------- 异步(多个大脑同时思考,多条路同时走)
三、案例实操
以案例,来演示Dubbo的一个使用流程。
3.1 主要过程
以之前的Spring Cloud项目为基础,有两个模块服务:
- 服务的提供者--------------------- 课程列表 list
- 服务的调用者、消费者--------- 课程价格 price
3.2 服务提供者的开发:list
模块
0.前提准备
创建项目:
这是一个基础的Maven项目:
在此基础上,进行升级:新建一个子模块
删掉src
目录,并新建一个子的maven项目
结果如下:
1.引入依赖
在父项目的pom中:
老师推荐不手写,因为有很多管理依赖配置的地方,经验不足容易漏掉
<?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>
<packaging>pom</packaging>
<modules>
<module>producer</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.imooc</groupId>
<artifactId>dubbo-practice</artifactId><!--1.1 老师的这个习惯挺好,备课用的prepare,正课改为practice-->
<version>0.0.1</version>
<name>dubbo-practice</name>
<description>Demo project for Spring Boot</description>
<!--1.2 相当于属性,一种变量,以方便最下面直接进行引用-->
<properties>
<java.version>1.8</java.version>
<spring-boot.version>2.1.12.RELEASE</spring-boot.version>
<dubbo.version>2.7.4.1</dubbo.version>
</properties>
<dependencyManagement>
<dependencies>
<!--2.1 引入Spring Boot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--2.2 引入apache的dubbo依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--同时还要排除一些依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
</project>
本节课的重点:是Dubbo,以前的熟悉的代码直接复制,并讲解重点以温习理解。
在子模块的pom中:
<?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">
<parent>
<artifactId>dubbo-practice</artifactId>
<groupId>com.imooc</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>producer</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--1.1 Spring Boot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--1.2 Spring Boot test相关的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--1.3 Dubbo相关的两个依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!--1.4 引入Zookeeper的依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--1.5 Web功能-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--1.6 mysql-connector,需要与MySQL版本对应-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--1.7 MyBatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
</project>
2.添加注解@Service
1.service层
注意:
在里,不需要写Controller层 。因为Controller 是建立在Web的思维,对外提供HTTP服务。
但是,现在的服务,并不是一个HTTP服务,而只是一个Dubbo服务,只把service写好即可。
/**
* 课程列表的服务:从数据库中,拿到课程列表并展示出来
*/
public interface CourseListService {
List<Course> getCourseList();
}
/**
* 课程列表服务的实现类
*/
@Service(version = "${demo.service.version}") // 注意:这里的注解,是来自apache.dubbo框架的,不是Spring的 // 版本号不写死,而是放在配置文件中
public class CourseListServiceImpl implements CourseListService {
@Resource
CourseMapper courseMapper;
@Override
public List<Course> getCourseList() {
return courseMapper.findValidCourses();
}
}
2.mapper层:
/**
* 课程的mapper类
*/
@Mapper // 让MyBatis可以找到它
@Repository
public interface CourseMapper {
@Select("SELECT * FROM course WHERE valid = 1") // 简单情况,可直接写在注解里 // 复杂:可以用MyBatis Generator方式,去自动生成XML,会有一些精细操作,比如判空
List<Course> findValidCourses();
}
3.把本模块服务(Dubbo),注册到Zookeeper上
也就是整合Dubbo和Zookeeper
# 指定版本:大版本.中版本.小版本
demo.service.version=1.0.0
# 数据库的配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/course_practice?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=1234abcd
# 日志配置
logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}
# 让mybatis,开启驼峰命名转换(将下划线的字段--->驼峰形式)
mybatis.configuration.map-underscore-to-camel-case=true
# 项目名称
spring.application.name=course-list
# dubbo的通信协议是dubbo(因为也可以是HTTP,所以这里要明示以下)
dubbo.protocol.name=dubbo
# dubbo的端口:-1表示随机找一个,因为它不重要,最终都是通过名字来查找。Dubbo会自动根据名字找到端口号
dubbo.protocol.port=-1
# dubbo的注册地址:是Zookeeper这个人服务注册与发现中心
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.registry.file=${user.home}/dubbo-cache/${spring.application.name}/dubbo.cache
# 扫描以下路径,因为dubbo的注解@Service,就在该路径下
dubbo.scan.base-packages=com.imooc.producer.service.impl
3.3 服务消费者的开发:price
模块
0.前提准备
新建项目:
1.引入依赖、编写配置文件
本子模块的依赖:
<?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">
<parent>
<artifactId>dubbo-practice</artifactId>
<groupId>com.imooc</groupId>
<version>0.0.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>consumer</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--1.1 Spring Boot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--1.2 Spring Boot测试相关的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--1.3 Dubbo相关的两个依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<!--1.4 引入Zookeeper的依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--1.5 Web功能-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--1.6 mysql-connector,需要与MySQL版本对应-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--1.7 MyBatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.imooc</groupId>
<artifactId>producer</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
配置文件:
# 因为本模块price是对外提供服务的
server.port=8084
# 指定版本:大版本.中版本.小版本
demo.service.version=1.0.0
# 数据库的配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/course_practice?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=1234abcd
# 日志配置
logging.pattern.console=%clr(%d{${LOG_DATEFORMAT_PATTERN:HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:%wEx}
# 让mybatis,开启驼峰命名转换(将下划线的字段--->驼峰形式)
mybatis.configuration.map-underscore-to-camel-case=true
# 项目名称
spring.application.name=course-price
# dubbo的通信协议是dubbo(因为也可以是HTTP,所以这里要明示以下)
dubbo.protocol.name=dubbo
# dubbo的端口:-1表示随机找一个,因为它不重要,最终都是通过名字来查找。Dubbo会自动根据名字找到端口号
dubbo.protocol.port=-1
# dubbo的注册地址:是Zookeeper这个人服务注册与发现中心
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.registry.file=${user.home}/dubbo-cache/${spring.application.name}/dubbo.cache
2.MVC三层
1.mapper层:
/**
* 课程价格的mapper类
*/
@Mapper
@Repository
public interface CoursePriceMapper {
@Select("SELECT * FROM course_price WHERE course_id = #{courseId}")
CoursePrice findCoursePrice(Integer courseId);
}
2.service层:
public interface CoursePriceService {
CoursePrice getCoursePrice(Integer courseId);
List<CourseAndPrice> getCoursesAndPrice();
}
/**
* 课程价格服务
*/
@Service // 因为本模块服务price,是对外暴露HTTP请求,所以使用的是Spring的
public class CoursePriceServiceImpl implements CoursePriceService {
@Resource
CoursePriceMapper coursePriceMapper;
@Reference(version = "${demo.service.version}") // 指定Dubbo服务(即list模块)的版本,会从Zookeeper寻找,从配置文件中读取
CourseListService courseListService;
// 1.单纯的查询课程价格
@Override
public CoursePrice getCoursePrice(Integer courseId) {
return coursePriceMapper.findCoursePrice(courseId);
}
// 2. 先拿到课程列表(一定依赖其他模块服务list),遍历一遍,最终匹配上价格
@Override
public List<CourseAndPrice> getCoursesAndPrice() {
List<CourseAndPrice> courseAndPriceList = new ArrayList<>();
List<Course> courses = courseListService.getCourseList(); // 利用到Dubbo通信,来直接使用其他模块服务
for (int i = 0; i < courses.size(); i++) {
Course course = courses.get(i);
// 将课程列表信息,与课程价格进行组合,组成一个courseAndPrice对象
if (course != null) {
CoursePrice coursePrice = getCoursePrice(course.getCourseId());
CourseAndPrice courseAndPrice = new CourseAndPrice();
courseAndPrice.setPrice(coursePrice.getPrice());
courseAndPrice.setName(course.getCourseName());
courseAndPrice.setId(course.getId());
courseAndPrice.setCourseId(course.getCourseId());
courseAndPriceList.add(courseAndPrice);
}
}
return courseAndPriceList;
}
}
3.controller层:
/**
* 课程价格的控制器
*/
@RestController // controller+能返回JSON数据
public class CoursePriceController {
@Resource
CoursePriceService coursePriceService;
// 只是自己的模块服务
@GetMapping("/price")
public Integer getCoursePrice(Integer courseId) {
CoursePrice coursePrice = coursePriceService.getCoursePrice(courseId);
return coursePrice.getPrice(); // 查询拿到某个课程Id的价格
}
// 在price模块中,整合两个服务
@GetMapping("/coursesAndPrice")
public List<CourseAndPrice> getCoursesAndPrice(){
List<CourseAndPrice> coursesAndPrice = coursePriceService.getCoursesAndPrice(); // 利用到Dubbo通信
return coursesAndPrice;
}
}
注意:远程调用的注解
3.4 两个模块服务的结果
1.前提:
- 要先启动Zookeeper
- 默认情况下,被依赖的类即生产者
list
模块,必须先启动;
我遇到的问题:
分析:
解决:
参考:
https://www.jianshu.com/p/181a69836fe9
2.结果
浏览器:
从接口的角度看,成功访问:
从IDEA的生产者的日志中看:
关于FeHelper:
我的:
综上所述,就完成Dubbo服务的创建、编写、调用。
3.5 小结
上面的Dubbo通信的项目,与原始的Spring Boot还是有区别的:
(1)在启动消费者之前,必须把环境(ZK、依赖的服务)准备好
(2)在生产者编写时,要记得配置:以让Dubbo去找到对应的地址进行扫描(只是生产者,否则报错)
(3)生产者:要配置dubbo相关的内容、实现类头上用dubbo的@Service
注解并指定版本
消费者:要配置dubbo相关的内容、属性调用时用dubbo的@Reference
注解并指定版本(以视为本地类)
- 其中:(2)(3)中,“要配置dubbo相关的内容” 的,生产者(Dubboo服务)、消费者区别
3.6 我对Zookeeper、Dubbo的理解
Zookeeper的架构图
定位:为分布式应用程序提供分布式协调服务的框架。
Dubbo的架构图:
定位:微服务之间,的高性能的RPC通信。
以上两者的关系:有点像以前学习《32.3 微服务入门》中的Spring Cloud这个微服务框架中的两个组件:
- Eureka组件------------------------------------------- Zookeeper框架
- 利用Feign,方便服务间调用--------------------- Dubbo框架
Comments | NOTHING