Dubbo
介绍
Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,以及SOA服务治理方案。
SOA
SOA(Service-Oriented Architecture),即面向服务的架构。
SOA是一种粗粒度、松耦合服务架构,服务之间通过简单、精确定义接口进行通讯,不涉及底层编程接口和通讯模型。
SOA可以看作是B/S模型、XML(标准通用标记语言的子集)/Web Service技术之后的自然延伸。
基本特征
SOA的实施具有几个鲜明的基本特征:
粗粒度的服务接口分级
松散耦合
可重用的服务
服务接口设计管理
标准化的服务接口
支持各种消息模式
精确定义的服务契约
SOA服务具有平台独立的自我描述XML文档。Web服务描述语言(WSDL, Web S
ervices Description Language)是用于描述服务的标准语言。
SOA 服务用消息进行通信,该消息通常使用XML Schema来定义(也叫做XSD, XML Schema Definition)。消费者和提供者或消费者和服务之间的通信多见于不知道提供者的环境中。服务间的通讯也可以看作企业内部处理的关键商业文档。
在一个企业内部,SOA服务通过一个扮演目录列表(directory listing)角色的登记处(Registry)来进行维护。应用程序在登记处(Registry)寻找并调用某项服务。统一描述,定义和集成(UDDI, Universal Description, Definition, and Integration)是服务登记的标准。
松耦合系统
具有中立的接口定义(没有强制绑定到特定的实现上)的特征称为服务之间的松耦合。松耦合系统的好处有两点,一点是它的灵活性,另一点是,当组成整个应用程序的每个服务的内部结构和实现逐渐地发生改变时,它能够继续存在。与之相反,紧耦合意味着应用程序的不同组件之间的接口与其功能和结构是紧密相连的,因而当需要对部分或整个应用程序进行某种形式的更改时,它们就显得非常脆弱。
架构图
角色
- Provider:暴露服务方称之为“服务提供者”。
- Consumer:调用远程服务方称之为“服务消费者”。
- Registry:注册中心.当Container启动时把所有可以提供的服务列表上-Registry中进行注册.作用:告诉Consumer提供了什么服务和服务方在哪里.
- Monitor:监听器,统计服务的调用次调和调用时间的日志服务称之为“服务监控中心”。
Container: Dubbo容器.依赖于Spring容器
注:
- 虚线都是异步访问,实线都是同步访问
- 蓝色虚线:在启动时完成的功能
- 红色虚线(实线)都是程序运行过程中执行的功能
- 所有的角色都是可以在单独的服务器上.所以必须遵守特定的协议.
运行原理:
- 启动容器,相当于在启动Dubbo的Provider
- 启动后会去注册中心进行注册.注册所有可以提供的服务列表
- 在Consumer启动后会去Registry中获取服务列表和Provider的地址.进行订阅.
- 当Provider有修改后,注册中心会把消息推送给Consummer 使用了观察者设计模式(又叫发布/订阅设计模式)
- 根据获取到的Provider地址,真实调用Provider中功能. 在Consumer方使用了代理设计模式.创建一个Provider方类的一个代理对象.通过代理对象获取Provider中真实功能,起到保护Provider真实功能的作用.
- Consumer和Provider每隔1分钟向Monitor发送统计信息,统计信息包含,访问次数,频率等
SpringBoot 整合 Dubbo
安装zookeeper
搭建 zookpeer 注册中心:
下载地址:https://zookeeper.apache.org/releases.html
-
解压下载的 tar.gz 包(版本为 zookpeer-3.4.14版本):
-
创建 data 目录,用于保存 zookpeer 的数据及日志:
-
在 conf 目录下,复制一份 zoo_sample.cfg 文件,并重命名为 zoo.cfg(这是 zookpeer 默认读取的配置文件):
-
修改 zoo.cfg 文件:
将 dataDir 的路径修改为刚刚创建的目录。 -
启动 zookpeer :
在 bin 目录下,执行 zkServer.cmd 命令启动。(默认会占用 2181 端口,注意3.5版本后可能占用8080端口)
安装dubbo admin
这是dubbo提供的一个开源的控制台,可以看到项目中在dubbo注册的服务接口详情,如果觉得麻烦也可以不安装,不影响使用
- 在 github 下载 dubbo admin 的源码:
git clone https://github.com/apache/dubbo-admin.git
注:如果github下载都比较慢,建议去github上直接下载,这边
下载后的源码结构如下:
由于 dubbo 2.7.x 版本采用的是前后端分离架构,所以分别进行打包。
打包 dubbo-admin-server 模块(管理控制台后端接口):
- 进入 dubbo-admin-server 目录,并执行 mvn clean package -Dmaven.test.skip=true 命令:
打包完成后,在target目录下使用 java -jar dubbo-admin-server-0.1.jar 启动后端接口(默认会占用 8080 端口):
- 打包 dubbo-admin-ui 模块(管理控制台前端页面):
由于该模块是采用 vue 前端工程方式构建,所以需要预先安装 node 环境,安装成功后,可使用 node -v 查看版本信息:
执行 npm install cnpm -g --registry=https://registry.npm.taobao.org 命令,将 node 包管理器切换为 cnpm
(因为npm安装插件都是从国外服务器下载,受网络影响大,可能出现异常):
执行 npm config get registry,查看 cnpm 是否配置成功:
然后在 dubbo-admin-ui 目录下执行 cnpm install 命令,安装依赖模块:
依赖模块安装完成后,执行 cnpm run dev 启动前端模块,待启动完成后通过 http://localhost:8081 即可访问控制台页面:
默认登陆用户名和密码都为为 root;如上,已成功看到 dubbo 管理控制台页面。
启用微服务测试
搭建 SpringBoot 多模块项目:
sp-dubbo:父模块
service-consumer:消费者模块
service-provider:提供者模块
service-interface:公共接口
sp-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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sp-dubbo</groupId>
<artifactId>sp-dubbo</artifactId>
<packaging>pom</packaging>
<version>1.0</version>
<name>sp-dubbo</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<lombok.version>1.16.20</lombok.version>
<spring-boot.version>2.1.6.RELEASE</spring-boot.version>
<dubbo.version>2.7.3</dubbo.version>
<dubbo-spring-boot-starter.version>2.7.3</dubbo-spring-boot-starter.version>
</properties>
<!-- 定义包信息,统一管理 -->
<dependencyManagement>
<dependencies>
<!--使用 spring-boot-dependencies 管理包依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Apache Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- Dubbo Spring Boot Starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-spring-boot-starter.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!-- 聚合子模块 -->
<modules>
<module>service-consumer</module>
<module>service-provider</module>
<module>service-interface</module>
</modules>
</project>
service-interface 模块配置:
<?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>sp-dubbo</artifactId>
<groupId>sp-dubbo</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>service-interface</groupId>
<artifactId>service-interface</artifactId>
<version>1.0</version>
<name>service-interface</name>
<dependencies>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
- User 类:
package inf.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
public class User implements Serializable {
private int userId;
private String userName;
private String address;
}
- IUserService 接口:
package inf.service;
import inf.entity.User;
import java.util.List;
public interface IUserService {
List<User> getUserList();
}
service-provider 模块配置:
- 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>sp-dubbo</artifactId>
<groupId>sp-dubbo</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>service-provider</groupId>
<artifactId>service-provider</artifactId>
<version>1.0</version>
<name>service-provider</name>
<dependencies>
<!-- 引入公共接口模块 -->
<dependency>
<groupId>service-interface</groupId>
<artifactId>service-interface</artifactId>
<version>1.0</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<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>
</dependencies>
</project>
- application.yml 配置:
# 启动端口
server:
port: 9001
dubbo:
# 提供者应用名称
application:
name: service-provider
# 使用dubbo协议暴露服务,端口为 20880
protocol:
name: dubbo
port: 20880
# 指定注册中心地址
registry:
address: zookeeper://127.0.0.1:2181
# 指定元数据中心
metadata-report:
address: zookeeper://127.0.0.1:2181
- UserServiceImpl 类:
package provider.service;
import inf.entity.User;
import inf.service.IUserService;
import org.apache.dubbo.config.annotation.Service;
import java.util.ArrayList;
import java.util.List;
/**
* 这里使用的是 dubbo 的 @Service 注解,用于暴露服务,并非 Spring的 @Service 注解
*/
@Service(version = "1.0")
public class UserServiceImpl implements IUserService {
public List<User> getUserList() {
User user = new User()
.setUserId(1)
.setUserName("Tom")
.setAddress("上海");
List<User> userList = new ArrayList<>();
userList.add(user);
return userList;
}
}
- StartProvider9001 启动类:
package provider;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubbo // 开启基于注解的 dubbo 功能
@SpringBootApplication
public class StartProvider9001 {
public static void main( String[] args ) {
SpringApplication.run(StartProvider9001.class, args);
}
}
service-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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sp-dubbo</artifactId>
<groupId>sp-dubbo</groupId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>service-consumer</groupId>
<artifactId>service-consumer</artifactId>
<version>1.0</version>
<name>service-consumer</name>
<dependencies>
<!-- 引入公共接口模块 -->
<dependency>
<groupId>service-interface</groupId>
<artifactId>service-interface</artifactId>
<version>1.0</version>
</dependency>
<!-- dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<exclusions>
<exclusion>
<artifactId>log4j</artifactId>
<groupId>log4j</groupId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<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>
</dependencies>
</project>
- application.yml 配置:
# 启动端口
server:
port: 9000
dubbo:
application:
name: service-consumer
registry:
address: zookeeper://127.0.0.1:2181
metadata-report:
address: zookeeper://127.0.0.1:2181
- UserController 类:
package consumer.controller;
import inf.entity.User;
import inf.service.IUserService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserController {
// @Reference注解用于引用暴露的服务,version参数则对应服务的版本号
@Reference(version = "1.0")
IUserService userService;
@RequestMapping("/getUserList")
public List<User> getUserList() {
return userService.getUserList();
}
}
- StartConsumer9000 启动类:
package consumer;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableDubbo // 开启基于注解的 dubbo 功能
@SpringBootApplication
public class StartConsumer9000 {
public static void main( String[] args ) {
SpringApplication.run(StartConsumer9000.class, args);
}
}
测试功能是否生效:
- 分别启动 provider 和 consumer 两个模块,然后访问:http://localhost:9000/getUserList:
- 如上,可成功获取到数据。再看下 dubbo 管理控制台是否有相应的服务:
如上,在 dubbo 管理控制台已成功获取到 consumer 和 provider 的服务接口信息。
总结
dubbo这种SOA项目和springcloud的还是很不同,采用接口的方式来实现dubbo服务,之后注册到zk上面;这种比较偏向于将项目拆分聚合行的,这种聚合拆分的比较细了,一般都是一层一个项目,比如web层一个,api服务接口层一个项目,实现接口层一个项目,业务层一个项目,操作数据库一层等,分的比较细;
其使用的注解@Service的使用,在如果公司的架构服务比较大的时候可以根据服务中心的不同,来用 group来给 服务分组,方便管理使用