微服务

微服务就是将一个完整的系统,按照业务功能,拆分成一个个独立的子系统,在微服务结构中,每个子系统就被称为“服务”。这些子系统能够独立运行在 web 容器中,它们之间通过 RPC 方式通信。

Dubbo

Dubbo 是一款高性能 Java RPC 框架,也叫微服务系统的协调者。在它这套体系中,一共有三种角色,分别是:服务提供者(provider)、服务消费者(consumer)、注册中心(zookeeper)。

服务提供者启动时,向注册中心注册自己提供的服务。服务消费者在启动时,向注册中心订阅自己所需的服务。注册中心返回服务提供者地址列表给消费者。此时消费者调用提供者提供的服务时,就跟在本地调用一样。

本文只是一个入门的 Demo,更多的 Dubbo 原理不在本文阐述范围内。

背景介绍

假设我们有一个论坛系统,这个系统有用户、帖子、评论、通知等模块

这些模块都可以拆分成一个个独立的子系统, 每个子系统都是一个 Maven Project ,这些子系统都有一个父系统,通常这个父系统只是一个空的 Maven Project,里面只有一个 pom 文件,这个 pom 文件定义了全局的版本号和依赖库。

还有另一种形式,就是每个模块都视为一个工程,比如用户模块是一个工程,帖子模块是一个工程,评论模块又是一个工程等等。每个工程下面又有多个子工程, 比如用户工程下面有 DAO 子工程,Service 子工程等等。这种情况是针对很大的项目而言。

下面以第二种形式,用户模块作为示例。

安装 Zookeeper

Zookeeper 是 Dubbo 推荐的服务注册中心,下载地址:

https://archive.apache.org/dist/zookeeper/zookeeper-3.4.9/

下载完之后解压,然后将 conf 目录下的 zoo_sample.cfg 文件的名字改成 zoo.cfg,否则启动会报错,提示找不到 zoo.cfg 文件。

修改完之后直接双击 bin 目录下的 zkServer.cmd,开启服务即可。

如图所示则说明开启成功

image

创建项目的组织结构

我使用的 IDE 是 intelliJ IDEA

创建父工程

创建一个 SpringBoot,这个工程作为父工程使用。

New Project

image

Type 选择 Maven POM

image

然后创建即可

创建子工程

右键父工程,New -> Module

image

image

image

Type 选择 Maven Project

然后一路 Next,Finish 即可。

创建完之后修改 pom.xml 文件,把

(1). <groupId>com.example</groupId>

(2). <version>0.0.1-SNAPSHOT</version>

(3). <properties><java.version>1.8</java.version></properties>

这三个参数去掉,因为 groupId、version 和 properties 会继承父工程的。

再修改 parent 参数,使 bbs-user-common 子工程继承 bbs-user 父工程

<parent>
	<groupId>com.example</groupId>
	<artifactId>bbs-user</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</parent>

修改后的完整的 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>
	<artifactId>bbs-user-common</artifactId>
	<packaging>jar</packaging>
	<name>bbs-user-common</name>
	<description>Demo project for Spring Boot</description>

	<!-- 继承说明:这里继承 bbs-user 父工程 -->
	<parent>
		<groupId>com.example</groupId>
		<artifactId>bbs-user</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>

	<!--依赖说明-->
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>


	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

同理,其他工程也是这样创建。

创建好的整个工程结构如下

image

定义服务接口

这个服务接口是提供给 provider 实现和 consumer 消费用的,所以需要把这个服务接口提取出来,打成 jar 包,提供给 provider 和 consumer 引用,所以这个服务接口我写在 bbs-user-common 工程里。

下面以获取用户信息为例

package com.example.bbs.user.common;

import java.util.Map;

public interface UserService {

    /**
     * 获取用户信息接口
     * @param name
     * @return
     */
    Map<String,Object> getUser(String name);
}

这样服务接口就写好了

定义服务提供者 provider

引入依赖

因为 provider 需要实现上面写的服务,所以要引入 bbs-user-common 工程。而且还要引入 dubbo。

在 pom.xml 文件里添加如下信息

<!--引入 bbs-user-common-->
<dependency>
	<groupId>com.example</groupId>
	<artifactId>bbs-user-common</artifactId>
	<version>${project.version}</version>
</dependency>

<!--引入 dubbo-->
<dependency>
	<groupId>com.alibaba.boot</groupId>
	<artifactId>dubbo-spring-boot-starter</artifactId>
	<version>0.2.0</version>
</dependency>

实现服务

package com.example.bbs.user.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.example.bbs.user.common.UserService;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;

@Service
@Component
public class UserServiceImpl implements UserService{

    /**
     * 实现服务。
     * 这里应该调用 Dao 层接口,查询数据库,然后再做业务逻辑
     * 因为这里我只是模拟,所以就只返回 name
     * @param name
     * @return
     */
    @Override
    public Map<String, Object> getUser(String name) {
        Map<String, Object> map = new HashMap<>();
        map.put("name",name);
        return map;
    }
}

这个 @Service 注解不是 Spring 包里的那个注解,而是 dubb 里提供的注解,包名是 com.alibaba.dubbo.config.annotation.Service

添加配置

在 application.yml 文件里添加 dubbo 配置

原本应该是 application.properties 文件的,但是我比较喜欢 yml 文件,所以就改成了 application.yml

完整的 application.yml 配置如下

dubbo:
  application:
    name: user-provider # 服务名
  registry:
    address: zookeeper://127.0.0.1:2181 # 注册中心地址
  protocol:
    name: dubbo # 指定通信协议
    port: 20880 # 通信端口,这里指的是与消费者间的通信协议与端口
  provider:
    timeout: 10000 # 配置全局调用服务超时时间,dubbo 默认是1s
    retries: 3 # 重试3次
    delay: -1

启动服务

开启服务之前确保已经开启了 Zookeeper

在启动类上加上注解 @EnableDubbo

然后启动 bbs-user-service 工程即可

可以看到服务已经成功启动了

image

定义服务消费者 Consumer

服务消费者我写在 bbs-user-web 工程里

引入依赖

引入跟服务提供者一样的依赖,而且还要引入 spring-web 依赖

<!--引入 spring-web-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	</dependency>

<!--引入 bbs-user-common-->
<dependency>
	<groupId>com.example</groupId>
	<artifactId>bbs-user-common</artifactId>
	<version>${project.version}</version>
</dependency>

<!--引入 dubbo-->
<dependency>
	<groupId>com.alibaba.boot</groupId>
	<artifactId>dubbo-spring-boot-starter</artifactId>
	<version>0.2.0</version>
</dependency>

调用服务

package com.example.bbs.user.web.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.example.bbs.user.common.UserService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

@RestController
public class UserController {

    @Reference
    private UserService userService;

    @RequestMapping(value = "/")
    public Map<String,Object> getUser(String name){
        return userService.getUser(name);
    }
}

添加配置

server:
  port: 8080
dubbo:
  application:
    name: user-consumer # 消息者名字
  registry:
    address: zookeeper://127.0.0.1:2181 # 注册中心地址

启动服务

image

可以看到服务已经在 8080 端口启动了

访问服务

image

可以看到成功输出了 “张三”

说明调用服务成功了

至此,SpringBoot+Dubbo 搭建一个简单的 Maven 多模块的 Demo 完成了

参考

原文链接:https://miansen.wang/2019/06/03/1/