赞
踩
dubbo作为阿里巴巴开源的微服务框架,提供了高性能的RPC调用。同时因为有阿里的背书,在国内市场得到了广泛应用,dubbo的开源工作在2018年2月阿里将项目捐献给apache基金会后,得到了更加广大的发展。
之前我们讲解了springcloud微服务体系的入门学习,今天同样带大家来快速入门掌握dubbo微服务框架的应用,让大家逐步了解springcloud alibaba体系
首先大家要了解到底什么是dubbo,他是一个组件,还是一门语言?实际上dubbo一个服务框架,一开始是用java编写,后续产生了go语言版本。因为dubbo本身自带了RPC调用功能,也就是组间调用。所以也称dubbo为RPC服务框架
我们来看官方对于dubbo的定义:
Apache Dubbo 是一款 RPC 服务开发框架,用于解决微服务架构下的服务治理与通信问题,官方提供了 Java、Golang 等多语言 SDK 实现。使用 Dubbo 开发的微服务原生具备相互之间的远程地址发现与通信能力, 利用 Dubbo 提供的丰富服务治理特性,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。Dubbo 被设计为高度可扩展,用户可以方便的实现流量拦截、选址的各种定制逻辑。
Dubbo3 定义为面向云原生的下一代 RPC 服务框架。3.0 基于 Dubbo 2.x 演进而来,在保持原有核心功能特性的同时, Dubbo3 在易用性、超大规模微服务实践、云原生基础设施适配、安全性等几大方向上进行了全面升级。
对于初学者,看起来是不是觉得晦涩难懂,但实际上大家要抓住核心词:服务治理
、服务通信
。这是dubbo框架所提供的核心功能。实际上也是微服务框架所要提供的核心功能。
以前我们讲解过什么是微服务。那么实际上微服务要解决的两个核心问题就是服务治理与通信。
服务治理是什么,就是服务的发现与分发,也就是管理有哪些种类的服务、每个种类的服务有多少个实例(可以简单理解为服务实际部署了多少台服务器),再次简化,就是如下的这张表格:
服务名 | ip |
---|---|
user-server 用户服务 | 192.168.101.1 |
user-server 用户服务 | 192.168.101.2 |
user-server 用户服务 | 192.168.101.3 |
order-server 订单服务 | 192.168.101.4 |
order-server 订单服务 | 192.168.101.5 |
order-server 订单服务 | 192.168.101.6 |
我们有处理用户信息的用户服务,部署了3台服务器,还有处理订单信息的订单服务,同样部署了3台。那么当用户在我们的网站上发起请求时,比如做了一个下单操作。
那么我的流程是要先获取这个用户的用户信息,也就要调用到用户服务,然后再创建订单,也就需要订单服务。那么用户肯定不会知道我们有多个用户服务和订单服务的,也不会知道我们部署这个服务的Ip地址。所以就需要一个东西管理这些服务,将用户的请求自动转发到对应的服务所对应的服务器上。
这样一个操作就是服务治理。
好了,再回到一开始的概念,我们前面说dubbo是服务框架,记住它不是组件,框架是结合具体的项目一起使用的,组件是可以单独部署的。
一般dubbo常常和zookeeper结合来实现服务治理,也就是用zk来做注册中心。如果不了解注册中心概念的,请先阅读上面列举的《什么是微服务》。
我们再说的直白一点,dubbo具体到java项目中,就是我们引入的一个jar包,我们只需要简单的引用,以及配置文件的配置,dubbo就可以帮助我们将我们的服务注册到zookeeper中,zk充当的就是上述那张表格的实时记录
而这些注册、调用的操作,都不需要我们手动时间,而是通过我们引入的dubbo包来自动实现的,这就是框架。
还有一个概念是“服务通信”,也称组间调用,也就是解决服务与服务之间的内部调用。
我们看上述的调用图,订单服务为了获取用户信息,需要调用用户服务,这里做习惯了单机架构的同学可能会疑问,你要获取用户信息,你写一个UserService
不就完了嘛,你搞什么幺蛾子还单独开个用户服务,这就要理解微服务的核心概念——专业的事专业的服务去干,用户的信息请让用户服务去管,如果一个服务管的东西太多,不就又回到了单机架构了嘛。
当然如果你服务请求的本身的量就不大,项目的规模也没有那么广,那么自然不需要如此细粒度的服务拆分。
我们知道接口调用,可以通过HttpClient
来实现,那么服务间调用的时候为什么不直接用httpclient呢,因为没有部署服务前我们根本都不知道服务的ip或域名,这是注册到注册中心后,注册中心告诉我们的。
当然你说我已经规定好了这个服务就要部署到固定的服务器上,那我可以直接用httpclient调用吗?当然可以了,万变不离其中,这本质上就是一个局域网内的接口调用。但是你想想,这足够灵活吗?
所以dubbo做了一个事情,也就是rpc的含义,让服务间调用,像本地调用一样简单!
什么意思?
就是我们调用用户服务时,只需要引一个UserService,然后按照类的形式来使用即可,但这个Serivice是的实现是定义在用户服务中的,这两个都不在一个项目里面,是怎么做到的呢,我们下面来实际搭建一个dubbo微服务,让大家深入感受一下
开始搭建之前,我们先说明本次演示项目的情况,我们将搭建一个订单服务,在订单服务中调用用户信息,以此来创建订单。
因为要用到注册中心,本次演示我们选用zookeeper,当然dubbo支持的注册中心不止zk,还有nacos与consul。
这里额外补充一点,因为dubbo官方讲解中常提到生产者与消费者的概念,对于初学者来讲会有些陌生。
但实际上这个概念非常好理解,比如我上述订单服务要获取用户信息就需要调用用户服务,那么用户服务就是生产者,因为用户服务要提供用户信息。订单服务要调用用户信息,即消费用户信息,所以订单服务是消费者,当然如果订单服务也需要对别的服务提供信息时,也需要将它注册成消费者。
具体我们进入到项目中来看。
如果你是刚学习微服务的同学,更加建议大家在搭建完dubbo后,系统学习下我之前书写的微服务入门专栏:
1、首先需要安装zookeeper,为了演示完整,我这里还额外安装了dubbo-admin,一个官方提供的可以可视化管理dubbo服务的web应用。不知道怎么安装的同学可以参考这篇文章:
1、我们需要创建一个maven空项目,作为父项目
注意这里我将版本号和包名做了调整
2、该项目下不需要任何目录,删除原有的src
目录
3、修改父项目的pom.xml
,统一jar包版本管理,注意这里我已经提前将需要用到的jar包的版本号做了声明,同时将子项目的服务名在modules
标签中提前说明了。如果后续有新子项目引入,需要在此标签中添加。还要将父项目的打包方式改为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> <groupId>wu.example</groupId> <artifactId>dubbo_wu_demo</artifactId> <version>${project.version}</version> <packaging>pom</packaging> <properties> <project.version>1.0.0-SNAPSHOT</project.version> <java.version>1.8</java.version> <maven.version>3.8.1</maven.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.3.7.RELEASE</spring-boot.version> <dubbo.version>3.1.2</dubbo.version> </properties> <modules> <module>user-server</module> <module>order-server</module> </modules> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>${dubbo.version}</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <version>${dubbo.version}</version> <type>pom</type> </dependency> </dependencies> </dependencyManagement> <build> <!-- 设置资源目录 --> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>${maven.version}</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>UTF-8</encoding> </configuration> </plugin> <!-- maven打包插件 --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot.version}</version> <executions> <execution> <goals> <!-- 将依赖的包一起打到jar中--> <goal>repackage</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
1、在该项目下右键新建一个子项目
2、创建用户服务,选择springboot框架,注意将包名调整为与父项目一致
3、为了演示方便,我们引入spring-web
依赖
4、修改user-server项目的pom
,引入dubbo-spring-boot-starter
,dubbo-dependencies-zookeeper
依赖,因为在父项目中已经声明过版本了,所以子项目中就不用在书写版本号了
<?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"> <parent> <artifactId>dubbo_wu_demo</artifactId> <groupId>wu.example</groupId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>user-server</artifactId> <version>${parent.version}</version> <name>user-server</name> <dependencies> <!-- dubbo client dependencies --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> </dependency> <!-- Zookeeper dependencies --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <type>pom</type> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </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> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </project>
5、同时为了项目的简洁清爽,以及版本的统一管理,我们做一些调整:
(1)删除多余不需要的文件,将.gitignore
,README.md
挪到父项目下
(2)配置文件格式改为yml(个人更喜欢yml格式,可以根据你的习惯)
6、创建一个UserServiceImpl
类,用来模拟根据用户ID提供用户信息,因为我们需要给订单服务调用,需要被注册为dubbo服务,所以需要使用@DubboService
注解
import org.apache.dubbo.config.annotation.DubboService; /** * @author benjamin_5 * @Description * @date 2022/11/19 */ @DubboService public class UserServiceImpl { public String getUserById(Integer id){ return "用户" + id; } }
7、修改配置文件properties.yml
更多的dubbo配置项可参考官方配置项介绍
# 应用名称
dubbo:
application:
name: user-server
protocol: # 指定通信规则
name: dubbo # 通信协议
port: -1 # dubbo协议端口,以供消费者访问,-1即为随机端口
registry: # 注册中心
id: zk-registry
address: zookeeper://127.0.0.1:2181
# 应用服务 WEB 访问端口
server:
port: 8081
8、作为生产者,也就是服务的提供者,我们还需要将其启动类上添加@EnableDubbo
注解
1、创建springboot项目order-server
,与user-server引用同样的依赖,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"> <parent> <artifactId>dubbo_wu_demo</artifactId> <groupId>wu.example</groupId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>order-server</artifactId> <version>${parent.version}</version> <name>order-server</name> <dependencies> <!-- dubbo client dependencies --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> </dependency> <!-- Zookeeper dependencies --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-dependencies-zookeeper</artifactId> <type>pom</type> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> </exclusion> </exclusions> </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> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </project>
2、修改配置文件
# 应用名称
dubbo:
application:
name: user-server
protocol: # 指定通信规则
name: dubbo # 通信协议
port: -1 # dubbo协议端口,以供消费者访问,-1即为随机端口
registry: # 注册中心
id: zk-registry
address: zookeeper://127.0.0.1:2181
# 应用服务 WEB 访问端口
server:
port: 8082
3、创建一个接口,用来模拟订单创建,需要在这个接口内调用用户服务的UserServiceImpl
,dubbo中引用service需要使用@DubboReference
但问题出现了,我们直接引用是会报错的,那这要怎么操作呢?不是说的像本地调用这么简单吗
4、毕竟还是在两个服务中,要想纯粹的直接调用肯定出问题,那可以想一想,先不考虑调用的问题,想让一个类能够在另一个服务中调用的方法是什么?
没错,就是引用,当然我们不能直接在order-server中引用user-server,不然要是用户服务也需要调订单服务的话,不就造成循环依赖了吗
5、我们创建一个server-api服务,专门用于存放service接口类
6、该服务不需要启动类,仅需要创建一个UserService接口,声明接口方法
项目依赖如下,因为没有启动类,所以要单独调整其打包方式:
<?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"> <parent> <artifactId>dubbo_wu_demo</artifactId> <groupId>wu.example</groupId> <version>1.0.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>service-api</artifactId> <version>${parent.version}</version> <name>user-server</name> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <skip>true</skip> <finalName>${project.name}</finalName> </configuration> </plugin> </plugins> </build> </project>
同时父项目pom
中要把该项目的module加上
7、创建完成后项目整体mvn install
一下,让server-api包存放到本地仓库,方便其他服务引用
8、在user-server,order-server中都引入server-api
<dependency>
<groupId>wu.example</groupId>
<artifactId>service-api</artifactId>
<version>${parent.version}</version>
</dependency>
9、修改user-server中的UserServiceImpl,让申明UserService接口
@DubboService
public class UserServiceImpl implements UserService {
@Override
public String getUserById(Integer id){
return "用户" + id;
}
}
10、同时order-server中则不再引用UserServiceImpl了,而是引用其接口类
@RestController
public class OrderController {
@DubboReference
private UserService userService;
@GetMapping("createOrder")
public String createOrder(Integer id){
String userName = userService.getUserById(id);
return userName + " createOrder success";
}
}
所以到这里,大家明白dubbo组间调用的使用方法了吗?
1、我们将订单服务和用户服务启动起来,注意先启动生产者user-server,再启动生产者order-server
我们使用zk可视化工具prettyZoo
,可以看到服务已经注册上去了
同时也可以用dubbo-admin
查看
这里我们可以看到,只有生产者会注册上去,而消费者只是从注册中心拉取服务
2、调用创建用户的接口
调用成功!
上述演示源码可在如下地址下载:
https://gitee.com/wuhanxue/dubbo_wu_demo
如上,我们针对dubbo框架的简单搭建就完成了, 实际还可以接入gateway来实现网关,或者也可以使用Nginx来做一层代理。后续我们一一
演示
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。