項目介紹
在微服務架構中,傳統的 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,如下。
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-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 腳本文件。我們看一下該表中的數據:
在 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", 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 分佈式的微服務架構就搭建好了,實際項目中可以直接拿這個來擴展。
源碼獲取:關注我的微信公衆號,回覆“源碼”即可獲取。還有更多架構等學習資源等你來獲取,更多關鍵字回覆可以留意後臺信息。