1. 程式人生 > >微服務中基於Spring Boot的maven分布式項目框架的搭建

微服務中基於Spring Boot的maven分布式項目框架的搭建

struct batis tmpl 接收 modules 展現 子模塊 server face

項目介紹

這裏搭建的是基於 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,如下。
    技術分享圖片
    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>
  1. 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 ...>

org.projectlombok lombok ``` 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 命令即可。如下: ![](http://i2.51cto.com/images/blog/201811/01/b7c2308ce82d9dc71f02b1905caf863a.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=) 在下一節,我們創建訂單服務提供模塊,在訂單服務提供模塊中,我們引入該公共模塊。 3. maven子工程microservice-order-provider模塊搭建 接下來我們搭建 maven 子工程中的訂單服務提供模塊 microservice-order-provider。 新建子模塊的方法和上面 microservice-common 模塊一模一樣,在命名的時候命名為 microservice-order-provider 即可。完成之後,來看一下該模塊中的 pom 文件: ``` microservice com.itcodai 1.0-SNAPSHOT ../microservice/pom.xml 4.0.0 microservice-order-provider jar com.itcodai microservice-common ${project.version} org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test org.mybatis.spring.boot mybatis-spring-boot-starter mysql mysql-connector-java ``` 可以看出,引入上一節我們自定義的 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 腳本文件。我們看一下該表中的數據: ![](http://i2.51cto.com/images/blog/201811/01/d1f434057281bb8b30633ab96bd001c6.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=) 在 OrderMapper 中寫兩個方法來查詢表中信息: ``` public interface OrderMapper { @Select("select * from t_order where id = #{id}") TOrder findById(Long id); @Select("select * from t_order") List 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 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 文件: ``` microservice com.itcodai 1.0-SNAPSHOT ../microservice/pom.xml 4.0.0 microservice-order-consumer jar com.itcodai microservice-common ${project.version} org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-test ``` 因為 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 getAll() { return restTemplate.getForObject(ORDER_PROVIDER_URL_PREFIX + "/provider/order/get/list", List.class); } } ``` 我們來講解一下 RestTemplate 的使用,在 Controller 中,我們定義了一個訂單服務提供者的 url 前綴,這是 microservice-order-provider 的服務地址,因為我們等會要遠程調用這個服務。restTemplate.getForObject 方法是 GET 請求方法,它有兩個參數: ``` url:請求地址 ResponseBean.class:HTTP 相應被轉換成的對象類型 ``` 對於實體類或者 List 均可以接收,同樣地,還有處理 POST 請求的方法 restTemplate.postForObject,該方法有三個參數,如下: ``` url:請求地址 requestMap:請求參數,封裝到map中 ResponseBean.class:HTTP響應被轉換成的對象類型 ``` 那麽整個流程即:訂單消費模塊不直接請求數據庫,而是通過 http 遠程調用訂單提供模塊的服務來獲取訂單信息。也就是說,在微服務裏,每個服務只關註自身的邏輯和實現,不用管其他服務的實現,需要獲取某個服務的數據時,只要調用該服務提供的接口即可獲取相應的數據。實現了每個服務專註於自身的邏輯,服務之間解耦合。 我們來測試一下,啟動 microservice-order-provider 和 microservice-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 分布式的微服務架構就搭建好了,實際項目中可以直接拿這個來擴展。

微服務中基於Spring Boot的maven分布式項目框架的搭建