【夯實Spring Cloud】Spring Cloud中基於maven的分散式專案框架的搭建

武哥聊程式設計發表於2018-10-31

本文屬於【夯實Spring Cloud】系列文章,該系列旨在用通俗易懂的語言,帶大家瞭解和學習Spring Cloud技術,希望能給讀者帶來一些乾貨。系列目錄如下:

【夯實Spring Cloud】Dubbo沉睡5年,Spring Cloud開始崛起!
【夯實Spring Cloud】Spring Cloud中基於maven的分散式專案框架的搭建
【夯實Spring Cloud】Spring Cloud中的Eureka服務註冊與發現詳解
【夯實Spring Cloud】Spring Cloud中如何完善Eureka中的服務資訊
【夯實Spring Cloud】Spring Cloud中使用Eureka叢集搭建高可用服務註冊中心
【夯實Spring Cloud】Spring Cloud中的Eureka和Zookeeper的區別在哪?
【夯實Spring Cloud】Spring Cloud中使用Ribbon實現負載均衡詳解(上)
【夯實Spring Cloud】Spring Cloud中使用Ribbon實現負載均衡詳解(下)
【夯實Spring Cloud】Spring Cloud中自定義Ribbon負載均衡策略
【夯實Spring Cloud】Spring Cloud中使用Feign實現負載均衡詳
【夯實Srping Cloud】Spring Cloud中使用Hystrix實現斷路器原理詳解(上)
【夯實Srping Cloud】Spring Cloud中使用Hystrix實現斷路器原理詳解(下)
【夯實Spring Cloud】Spring Cloud中使用Zuul實現路由閘道器詳解
【夯實Spring Cloud】Spring Cloud分散式配置中心詳解
【夯實Spring Cloud】未完待續


專案介紹

在微服務架構中,傳統的 maven 專案已經無法滿足,開始走向分散式架構,本專案主要搭建一個空的 maven 分散式架構,可以運用到實際專案中進行擴充套件,可以在文末獲取原始碼和更多資源。

這裡搭建的是基於 maven 的分散式工程,因為在一個專案中,多個微服務是屬於同一個工程,只不過是提供不同的服務而已,再加上 IDEA 是預設一個視窗開啟一個專案工程(這點和 eclipse 不同),如果專案大,不用 maven 聚合工程的話,那估計會開啟十幾個視窗……會崩潰……而且在架構上,也應該使用 maven 分散式工程來搭建微服務架構。這裡手把手教大家在 IDEA 中搭建基於 maven 分散式的 Spring Cloud 微服務工程架構。

1. maven分散式工程架構

首先來看一下 maven 分散式工程的基本架構,如下:

microservice
---- microservice-common
---- microservice-order-provider
---- microservice-order-consumer

在 IDEA 中,並沒有這個結構化的展示,這幾個模組都是平級的方式展現在我們眼前,但是彼此有依賴關係,體現在 pom.xml 檔案中,在下文會詳細說明。microservice 為父工程模組,主要用來定義整個分散式工程的依賴版本;microservice-common 為公共模組,主要用來定義一些公共的元件,比如實體類等;microservice-order-provider 為訂單服務提供者模組,提供訂單資訊,實際專案中可能還有其他服務提供模組;microservice-order-consumer 為服務消費模組,當然了,消費模組也可能有很多,這裡只建立一個,實際專案中可以在此基礎上進行擴充套件。

2. maven父工程microservice的搭建

開啟 IDEA, File -> New -> New Project,然後選擇 Empty Project,如下。
maven分散式專案的建立
Next,然後給 maven 分散式專案起個名兒,如 maven_distributed。
在這裡插入圖片描述
接下來會彈出視窗讓我們新建 modules,點選 + 號,新建一個父工程,也就是一個父 module。然後我們選擇 maven 工程,選擇 jdk 版本和模板,模板也可以不選擇,我這裡就沒有選擇,自己搭建即可。

在這裡插入圖片描述

Next,需要輸入 GroupId 和 ArtifactId,這和普通的 maven 工程沒什麼兩樣,如:

GroupId:com.itcodai
ArtifactId:microservice

建立好之後,該父工程 microservice 是個空的 maven 工程,只有 src 目錄和 pom.xml 檔案,在父工程中我們主要做什麼呢?父工程中主要用來定義一些依賴的版本,子工程在建立的時候繼承該父工程,就可以使用對用的依賴,不需要指定版本號。同時,如果有版本相關的修改,只要在父工程中修改即可,這是 maven 分散式工程的好處之一,它就相當於 Java 中的抽象父類。

新建立的空 maven 工程沒有指定其 <packaging> 型別,maven 父工程需要指定 packaging 型別為 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>com.itcodai</groupId>
    <artifactId>microservice</artifactId>
    <version>1.0-SNAPSHOT</version>
    
    <packaging>pom</packaging>
    
</project>

然後我們來定義一些依賴和相應的版本,依賴的版本我們定義在 properties 標籤內,如下:

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
	<!-- 省略其他內容 -->
	<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring-cloud.version>Edgware.SR1</spring-cloud.version>
        <spring-boot.version>2.0.3.RELEASE</spring-boot.version>
        <mysql.version>5.1.46</mysql.version>
        <mybatis.version>1.3.2</mybatis.version>
        <lombok.version>1.16.18</lombok.version>
    </properties>
</prject>

如上,我們定義了專案的編碼為 UTF-8,編譯版本為 jdk8,其他依賴版本為:

  • Spring Cloud 的版本為 Edgware.SR1,Spring Cloud 的版本號定義的非常“奇怪”,不是我們平常看到的幾點幾版本,它是由地名兒來命名的;
  • Spring Boot 版本為當前最新版本 2.0.3.RELEASE;
  • mysql 版本為 5.1.14;
  • mybatis 版本為 1.3.2;
  • lombok版本為 1.16.8.

其他依賴在專案使用到時,再新增即可,這裡先定義這麼多。在定義版本時,要注意的是不同的依賴版本之間會有影響,有些最新的版本不支援其他依賴的低版本一起使用,比如 mysql 的版本太低就不行,例如 5.0.4 版本就無法和最新的 mybatis 一起使用,這些在實際專案中都踩過坑,所以大家在學習的時候要多嘗試,多總結,最新版本不是不好用,有時候是用不好。但是隻要認真探索,多踩坑才能進步。

定義了依賴版本之後,接下來我們就在父工程中定義依賴管理,放在 <dependencyManagement> 標籤中,如下:

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
	<!-- 省略其他內容 -->
	<dependencyManagement>
        <dependencies>
            <!-- 定義 spring cloud 版本 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- 定義 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>
            <!-- 定義 mysql 版本 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!-- 定義 mybatis 版本 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.version}</version>
            </dependency>
            <!-- 定義 lombok 版本 -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

使用 ${} 來定義上面 <properties> 標籤中定義的版本即可。最後我們定義一下 maven 外掛,如下:

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
	<!-- 省略其他內容 -->
	<build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

3. maven子工程microservice-common模組搭建

接下來我們搭建 maven 子工程中的公共模組 microservice-common,新建子模組,我們要選擇 module,步驟為: File -> New -> Module,然後選擇 maven,這和上面建立父工程一模一樣,下一步的時候需要注意:

在這裡插入圖片描述

這裡要注意的是,使用 IDEA 建立子模組的時候,不需要選擇 “Add as module to” 這一項,預設是選擇了我們剛剛建立的父工程 microservice,我們在 Parent 項選擇剛剛建立的 microservice 模組即可,然後給該子模組起名為 microservice-common。建立好之後,我們來看一下該模組的 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>microservice</artifactId>
        <groupId>com.itcodai</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../microservice/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>microservice-common</artifactId>
    
</project>

可以看到,在 microservice-common 模組中,有個 <parent> 標籤,裡面內容是父工程 microservice 的相關資訊,包括依賴的路徑也標出來了,這樣 microservice-common 模組和 microservice 模組就建立了關聯。子模組的 <packaging> 型別我們定義成 jar 即可。

<packaging>jar</packaging>

microservice-common 模組我們主要定義一些公共的元件,本節課中,我們先定義一個訂單實體類,因為這個實體在其他模組也要用到,所以我們定義在這個公共模組中,那麼在該模組中,目前我們只需要引入 lombok 即可。如下:

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
    <!-- 省略其他內容 -->

    <!-- 當前Module需要用到的依賴,按自己需求新增,版本號在父類已經定義了,這裡不需要再次定義 -->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

lombok 依賴主要是用在實體類上,我們不用自己去定義構造方法,不用自己去生成 get 和 set 方法了,很方便。引入了依賴之後,我們去建立一個訂單實體類。

@AllArgsConstructor
@NoArgsConstructor
@Data
public class TOrder {

    private Long id; // 主鍵id
    private String name; // 商品名稱
    private Double price; // 商品價格
    private String dbSource; // 所存的資料庫
}

解釋一下該實體類上的幾個註解:

@AllArgsConstructor 註解:表示生成帶有所有屬性的構造方法
@NoArgsConstructor 註解:表示生成不帶引數的構方法
@Data 註解:表示生成get和set方法

可以看出,使用 lombok 很方便,省去了很多繁瑣的程式碼。到此為止,microservice-common 模組基本上就寫完了,在實際專案中,可能還有別的實體類或者工具類等需要定義,視具體情況而定。

接下來我們需要把這個模組打包,讓其他模組引用,這樣其他模組就可以使用該模組中的公共元件了,就跟普通的 maven 依賴一樣。如何打包呢?點開右邊的 Maven Projects,我們可以看到目前專案中有兩個模組,一個父工程和一個公共子工程模組,然後開啟公共模組,執行 maven 中的 clean 和 install 命令即可。如下:

在這裡插入圖片描述

在下一節,我們建立訂單服務提供模組,在訂單服務提供模組中,我們引入該公共模組。

3. maven子工程microservice-order-provider01模組搭建

接下來我們搭建 maven 子工程中的訂單服務提供模組 microservice-order-provider01
新建子模組的方法和上面 microservice-common 模組一模一樣,在命名的時候命名為 microservice-order-provider01 即可。完成之後,來看一下該模組中的 pom 檔案:

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
    <parent>
        <artifactId>microservice</artifactId>
        <groupId>com.itcodai</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../microservice/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>microservice-order-provider01</artifactId>
    <packaging>jar</packaging>

    <!-- 當前Module需要用到的依賴,按自己需求新增,版本號在父類已經定義了,這裡不需要再次定義 -->
    <dependencies>
        <!-- 引入自己定義的 microservice-common 通用包,可以使用common模組中的TOrder類 -->
        <dependency>
            <groupId>com.itcodai</groupId>
            <artifactId>microservice-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- spring boot web 依賴 -->
        <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>
        </dependency>
        <!-- mybatis 依賴 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!-- mysql 依賴 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>
</project>

可以看出,引入上一節我們自定義的 microservice-common 模組和引入其他依賴沒什麼兩樣,版本我們使用 ${project.version} 來跟著專案版本走即可。其他依賴我們只需要引入即可,不需要定義版本號。

由於這是服務提供模組,我們需要在表中查詢出訂單資訊,然後將資訊通過介面提供給呼叫方,所以在該模組中,我們需要整合一下 mybatis,mybatis 的整合我在 Spring Boot 課程中有詳細的講解,不是這門課的重點,mybatis 的相關配置和程式碼可以本課程下載原始碼檢視,這裡主要使用註解的方式。

我們看一下 application.yml 配置檔案中的部分資訊:

# 服務埠號
server:
  port: 8001
spring:
  application:
    name: microservice-order # 對外暴露的服務名稱

spring.application.name 是用來定義服務的名稱,在後面的課程會詳細的說明。TOrder實體對應的表以及資料見 order.sql 指令碼檔案。我們看一下該表中的資料:

在這裡插入圖片描述

在 OrderMapper 中寫兩個方法來查詢表中資訊:

public interface OrderMapper {

    @Select("select * from t_order where id = #{id}")
    TOrder findById(Long id);

    @Select("select * from t_order")
    List<TOrder> findAll();
}

我們在 Controller 層寫兩個介面來測試一下:

@RestController
@RequestMapping("/provider/order")
public class OrderProviderController {

    @Resource
    private OrderService orderService;

    @GetMapping("/get/{id}")
    public TOrder getOrder(@PathVariable Long id) {
        return orderService.findById(id);
    }

    @GetMapping("/get/list")
    public List<TOrder> getAll() {
        return orderService.findAll();
    }
}

在瀏覽器中輸入localhost:8001/provider/order/get/list,如果能查出來兩條記錄,並以 json 格式輸出到瀏覽器,如下,說明服務提供模組功能正常。

[{"id":1,"name":"跟武哥一起學 Spring Boot","price":39.99,"dbSource":"microservice01"},{"id":2,"name":"跟武哥一起學 Spring cloud","price":39.99,"dbSource":"microservice01"}]

4. maven子工程microservice-order-consumer模組搭建

接下來我們搭建 maven 子工程中的訂單服務消費模組 microservice-order-consumer
新建子模組的方法和上面兩個子 模組一模一樣,在命名的時候命名為 microservice-order-consumer 即可。完成之後,來看一下該模組中的 pom 檔案:

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
    <parent>
        <artifactId>microservice</artifactId>
        <groupId>com.itcodai</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../microservice/pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>microservice-order-consumer</artifactId>
    <packaging>jar</packaging>

    <!-- 當前Module需要用到的依賴,按自己需求新增,版本號在父類已經定義了,這裡不需要再次定義 -->
    <dependencies>
        <!-- 引入自己定義的 microservice-common 通用包,可以使用common模組中的Order類 -->
        <dependency>
            <groupId>com.itcodai</groupId>
            <artifactId>microservice-common</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- spring boot web 依賴 -->
        <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>
        </dependency>
    </dependencies>
</project>

因為 microservice-order-consumer 模組主要是用來呼叫 microservice-order-provider01 模組提供的訂單資訊,所以在 microservice-order-consumer 模組中我們不需要引入 mybatis 和 mysql 相關的依賴,因為不用運算元據庫。當然了,在實際專案中,根據具體需求,如果需要操作其他表,那麼還是要引入持久層依賴的。

在微服務都是以 HTTP 介面的形式暴露自身服務的,因此在呼叫遠端服務時就必須使用 HTTP 客戶端。Spring Boot 中使用的是 RestTemplate,首先,我們寫一個配置類,將 RestTemplate 作為一個 Bean 交給 Spring 來管理。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTmplateConfig {

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

有了 RestTemplate,接下來我們可以在 Controller 中注入該 RestTemplate 來呼叫 microservice-order-provider01 提供的服務了,如下:

@RestController
@RequestMapping("/consumer/order")
public class OrderConsumerController {

    // 訂單服務提供者模組的 url 字首
    private static final String ORDER_PROVIDER_URL_PREFIX = "http://localhost:8001";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/get/{id}")
    public TOrder getOrder(@PathVariable Long id) {

        return restTemplate.getForObject(ORDER_PROVIDER_URL_PREFIX + "/provider/order/get/" + id, TOrder.class);
    }

    @SuppressWarnings("unchecked")
    @GetMapping("/get/list")
    public List<TOrder> getAll() {
        return restTemplate.getForObject(ORDER_PROVIDER_URL_PREFIX + "/provider/order/get/list", List.class);
    }
}

我們來講解一下 RestTemplate 的使用,在 Controller 中,我們定義了一個訂單服務提供者的 url 字首,這是 microservice-order-provider01 的服務地址,因為我們等會要遠端呼叫這個服務。restTemplate.getForObject 方法是 GET 請求方法,它有兩個引數:

url:請求地址
ResponseBean.class:HTTP 相應被轉換成的物件型別

對於實體類或者 List 均可以接收,同樣地,還有處理 POST 請求的方法 restTemplate.postForObject,該方法有三個引數,如下:

url:請求地址
requestMap:請求引數,封裝到map中
ResponseBean.class:HTTP響應被轉換成的物件型別

那麼整個流程即:訂單消費模組不直接請求資料庫,而是通過 http 遠端呼叫訂單提供模組的服務來獲取訂單資訊。也就是說,在微服務裡,每個服務只關注自身的邏輯和實現,不用管其他服務的實現,需要獲取某個服務的資料時,只要呼叫該服務提供的介面即可獲取相應的資料。實現了每個服務專注於自身的邏輯,服務之間解耦合。

我們來測試一下,啟動 microservice-order-provider01microservice-order-consumer 兩個服務,在瀏覽器中輸入 localhost:8080/consumer/order/get/list,如果瀏覽器中能查到資料庫中的兩條記錄,說明服務呼叫成功。

[{"id":1,"name":"跟武哥一起學 Spring Boot","price":39.99,"dbSource":"microservice01"},{"id":2,"name":"跟武哥一起學 Spring cloud","price":39.99,"dbSource":"microservice01"}]

到此為止,基於 maven 分散式的微服務架構就搭建好了,實際專案中可以直接拿這個來擴充套件。


原始碼下載地址:https://gitee.com/eson15/springcloud_study

更多優質文章請關注我的微信公眾號【武哥聊程式設計】,回覆“資源”、“架構”、“簡歷”等關鍵詞,可以領取海量優質的視訊學習資源。大家共同進步。
在這裡插入圖片描述

相關文章