1. 程式人生 > >微服務中基於Spring Boot的maven分散式專案框架的搭建

微服務中基於Spring Boot的maven分散式專案框架的搭建

專案介紹

在微服務架構中,傳統的 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。

maven分散式專案的建立

接下來會彈出視窗讓我們新建 modules,點選 + 號,新建一個父工程,也就是一個父 module。然後我們選擇 maven 工程,選擇 jdk 版本和模板,模板也可以不選擇,我這裡就沒有選擇,自己搭建即可。

maven父工程的搭建

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,這和上面建立父工程一模一樣,下一步的時候需要注意:

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-provider模組搭建

接下來我們搭建 maven 子工程中的訂單服務提供模組 microservice-order-provider
新建子模組的方法和上面 microservice-common 模組一模一樣,在命名的時候命名為 microservice-order-provider 即可。完成之後,來看一下該模組中的 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-provider</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 指令碼檔案。我們看一下該表中的資料:

order表資料

在 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-provider 模組提供的訂單資訊,所以在 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"