Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring 框架无缝集成。
Dubbo 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
准备工作
1.安装 zookeeper
进入 zookeeper 的官网
http://zookeeper.apache.org/
Getting Started -> Download
Download -> archive
选择相应的版本进行下载
在下载完成解压后的 conf 目录下,复制一份 zoo_sample.cfg 改名为 zoo.cfg,配置 dataDir 来确定临时数据存储的目录,保存退出,来到 bin 目录下,启动 zkServer.cmd。
我们可以看到 zookeeper 客户端的端口号是 2181,与我们在 zoo.cfg 中配置的一致。
2.安装 Dubbo 的管理控制台
Dubbo 的源码已经托管到了 github 下,跟随官方文档到 github,下载 dubbo-admin
https://github.com/apache/dubbo-admin
新版 dubbo-admin 分为前后端两个部分。
后端 dubbo-admin-server 是一个 Spring Boot 项目,为了方便以后运行,我们可以用 maven 的 mvn clean package -Dmaven.test.skip=true 命令将项目打成 jar 包,然后再用 java -jar 命令启动。
前端 dubbo-admin-ui 是一个 vue 项目,运行需要 node.js 环境,安装好 node.js 环境后,用命令行进入 dubbo-admin-ui 目录下,使用 npm install 命令下载依赖包,再使用 npm run dev 运行项目。
在浏览器中访问 localhost:8081,默认的账号密码都是 root。
这样 Dubbo 的管理控制台就安装成功了!
值得注意的是,我一开始不懂前后端分离项目的部署是如何进行的,走了很多的弯路,正确的顺序是应该先启动后端的 dubbo-admin-server,默认的端口号是 8080,在前端的 dubbo-admin-ui 的 config 目录下有个 index.js 文件,里面配置了后端的端口号是 8080,前端项目的端口号是 8081,我们通过 8081 端口就可以访问这个整体的前后端分离项目了。
Dubbo Hello World
接下来通过一个小 Demo 来带大家快速了解 Dubbo 的使用。
先在 IDEA 中创建一个空工程,再创建三个 module,名称分别为 gmall-interface,user-service-provider,order-service-consumer。
gmall-interface 主要负责一些实体类以及公共接口的声明,我们这个 Demo 要做的是在 OrderService 中通过 UserService 的 getUserAddressList() 方法查到用户的住址,所以 user-service-provider 为服务的提供者,order-service-consumer 为服务的消费者。
gmall-interface 的代码示例:
UserAddress.java
package com.ml.gmall.bean;
import java.io.Serializable;
public class UserAddress implements Serializable {
private Integer id;
private String userAddress;
private String userId;
private String consignee;
private String phoneNum;
private String isDefault;
// 省略构造器和 set/get 方法
}
OrderService.java
package com.ml.gmall.service;
import com.ml.gmall.bean.UserAddress;
import java.util.List;
public interface OrderService {
public List<UserAddress> initOrder(String userId);
}
UserService.java
package com.ml.gmall.service;
import com.ml.gmall.bean.UserAddress;
import java.util.List;
public interface UserService {
public List<UserAddress> getUserAddressList(String userId);
}
user-service-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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ml.gmall</groupId>
<artifactId>user-service-provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>user-service-provider</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.ml.gmall</groupId>
<artifactId>gmall-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
MyDubboConfig.java
package com.ml.gmall.config;
import java.util.ArrayList;
import java.util.List;
import com.ml.gmall.service.UserService;
import org.apache.dubbo.config.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyDubboConfig {
@Bean
public ApplicationConfig applicationConfig() {
ApplicationConfig applicationConfig = new ApplicationConfig();
applicationConfig.setName("boot-user-service-provider");
return applicationConfig;
}
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setProtocol("zookeeper");
registryConfig.setAddress("127.0.0.1:2181");
return registryConfig;
}
@Bean
public ProtocolConfig protocolConfig() {
ProtocolConfig protocolConfig = new ProtocolConfig();
protocolConfig.setName("dubbo");
protocolConfig.setPort(20882);
return protocolConfig;
}
@Bean
public ServiceConfig<UserService> userServiceConfig(UserService userService) {
ServiceConfig<UserService> serviceConfig = new ServiceConfig<>();
serviceConfig.setInterface(UserService.class);
serviceConfig.setRef(userService);
serviceConfig.setVersion("1.0.0");
// 配置每一个 method 的信息
MethodConfig methodConfig = new MethodConfig();
methodConfig.setName("getUserAddressList");
methodConfig.setTimeout(1000);
// 将 method 的设置关联到 service 配置中
List<MethodConfig> methods = new ArrayList<>();
methods.add(methodConfig);
serviceConfig.setMethods(methods);
return serviceConfig;
}
}
这段代码主要负责配置 Dubbo 的注册中心以及服务的相关属性。
UserServiceImpl.java
package com.ml.gmall.service.impl;
import java.util.Arrays;
import java.util.List;
import com.ml.gmall.bean.UserAddress;
import com.ml.gmall.service.UserService;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
@Service
@Component
public class UserServiceImpl implements UserService {
@Override
public List<UserAddress> getUserAddressList(String userId) {
UserAddress address1 = new UserAddress(1, "山东省青岛市", "1", "张三", "6666", "Y");
UserAddress address2 = new UserAddress(2, "四川省成都市", "1", "李四", "8888", "N");
if (Math.random() > 0.5) {
throw new RuntimeException();
}
return Arrays.asList(address1, address2);
}
}
@Service 注解表示要暴漏服务。
最后要在主启动类类上标注@EnableDubbo 注解,表示要开启基于注解的 Dubbo 功能。
在 application.properties 中配置端口号为 8082,因为 8080 和 8081 已经分别被管理控制台的后端和前端占用,最后启动 serServiceProviderApplication 的 main 方法,打开 Dubbo 的管理控制台,发现服务已经注册到注册中心中了。
order-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 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.2.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.ml.gmall</groupId>
<artifactId>order-service-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>order-service-consumer</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.ml.gmall</groupId>
<artifactId>gmall-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</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.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>4.2.0</version>
</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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.properties
server.port=8083
dubbo.application.name=order-service-consumer
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.monitor.protocol=registry
OrderServiceImpl.java
package com.ml.gmall.service.impl;
import com.ml.gmall.bean.UserAddress;
import com.ml.gmall.service.OrderService;
import com.ml.gmall.service.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
@Service
public class OrderServiceImpl implements OrderService {
@Reference(loadbalance = "random", timeout = 1000, version = "1.0.0")
UserService userService;
@Override
public List<UserAddress> initOrder(String userId) {
System.out.println("用户id:" + userId);
List<UserAddress> addressList = userService.getUserAddressList(userId);
return addressList;
}
}
OrderController.java
package com.ml.gmall.controller;
import com.ml.gmall.bean.UserAddress;
import com.ml.gmall.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class OrderController {
@Autowired
OrderService orderService;
@ResponseBody
@RequestMapping("/initOrder")
public List<UserAddress> initOrder(@RequestParam("uid") String userId) {
return orderService.initOrder(userId);
}
}
最后启动 OrderServiceConsumerApplication 的 main 方法,在浏览器中访问 http://localhost:8083/initOrder?uid=1,就可以查到地址信息了!