本文將以原理+實戰的方式,首先對「微服務」相關的概念進行知識點掃盲,而後開始手把手教你搭建這一整套的微服務系統。前端
https://github.com/bz51/Sprin...java
這套系統搭建完以後,那可就厲害了:mysql
咳咳,敲黑板啦!筆記趕忙記起來,課後我要檢查的!檢查不合格的同窗放學後留下來!git
微服務一次近幾年至關火,成爲程序猿飯前便後裝逼熱門詞彙,你不對它有所瞭解如何在程序猿裝逼圈子裏混?下面我用最爲通俗易懂的語言介紹它。github
要講清楚微服務,我先要從一個系統架構的演進過程講起。web
我想你們最最最熟悉的就是單機結構,一個系統業務量很小的時候全部的代碼都放在一個項目中就行了,而後這個項目部署在一臺服務器上就行了。整個項目全部的服務都由這臺服務器提供。這就是單機結構。
那麼,單機結構有啥缺點呢?我想缺點是顯而易見的,單機的處理能力畢竟是有限的,當你的業務增加到必定程度的時候,單機的硬件資源將沒法知足你的業務需求。此時便出現了集羣模式,往下接着看。redis
集羣模式在程序猿界由各類裝逼解釋,有的讓你根本沒法理解,其實就是一個很簡單的玩意兒,且聽我一一道來。spring
單機處理到達瓶頸的時候,你就把單機複製幾份,這樣就構成了一個「集羣」。集羣中每臺服務器就叫作這個集羣的一個「節點」,全部節點構成了一個集羣。每一個節點都提供相同的服務,那麼這樣系統的處理能力就至關於提高了好幾倍(有幾個節點就至關於提高了這麼多倍)。sql
但問題是用戶的請求究竟由哪一個節點來處理呢?最好可以讓此時此刻負載較小的節點來處理,這樣使得每一個節點的壓力都比較平均。要實現這個功能,就須要在全部節點以前增長一個「調度者」的角色,用戶的全部請求都先交給它,而後它根據當前全部節點的負載狀況,決定將這個請求交給哪一個節點處理。這個「調度者」有個牛逼了名字——負載均衡服務器。docker
集羣結構的好處就是系統擴展很是容易。若是隨着大家系統業務的發展,當前的系統又支撐不住了,那麼給這個集羣再增長節點就好了。可是,當你的業務發展到必定程度的時候,你會發現一個問題——不管怎麼增長節點,貌似整個集羣性能的提高效果並不明顯了。這時候,你就須要使用微服務結構了。
先來對前面的知識點作個總結。
從單機結構到集羣結構,你的代碼基本無須要做任何修改,你要作的僅僅是多部署幾臺服務器,沒太服務器上運行相同的代碼就好了。可是,當你要從集羣結構演進到微服務結構的時候,以前的那套代碼就須要發生較大的改動了。因此對於新系統咱們建議,系統設計之初就採用微服務架構,這樣後期運維的成本更低。但若是一套老系統須要升級成微服務結構的話,那就得對代碼大動干戈了。因此,對於老系統而言,到底是繼續保持集羣模式,仍是升級成微服務架構,這須要大家的架構師深思熟慮、權衡投入產出比。
OK,下面開始介紹所謂的微服務。
微服務就是將一個完整的系統,按照業務功能,拆分紅一個個獨立的子系統,在微服務結構中,每一個子系統就被稱爲「服務」。這些子系統可以獨立運行在web容器中,它們之間經過RPC方式通訊。
舉個例子,假設須要開發一個在線商城。按照微服務的思想,咱們須要按照功能模塊拆分紅多個獨立的服務,如:用戶服務、產品服務、訂單服務、後臺管理服務、數據分析服務等等。這一個個服務都是一個個獨立的項目,能夠獨立運行。若是服務之間有依賴關係,那麼經過RPC方式調用。
這樣的好處有不少:
那麼問題來了,當採用微服務結構後,一個完整的系統可能有不少獨立的子系統組成,當業務量漸漸發展起來以後,而這些子系統之間的關係將錯綜複雜,並且爲了可以針對性地增長某些服務的處理能力,某些服務的背後多是一個集羣模式,由多個節點構成,這無疑大大增長了運維的難度。微服務的想法好是好,但開發、運維的複雜度實在是過高。爲了解決這些問題,阿里巴巴的Dubbo就橫空出世了。
Dubbo是一套微服務系統的協調者,在它這套體系中,一共有三種角色,分別是:服務提供者(下面簡稱提供者)、服務消費者(下面簡稱消費者)、註冊中心。
你在使用的時候須要將Dubbo的jar包引入到你的項目中,也就是每一個服務都要引入Dubbo的jar包。而後當這些服務初始化的時候,Dubbo就會將當前系統須要發佈的服務、以及當前系統的IP和端口號發送給註冊中心,註冊中心便會將其記錄下來。這就是服務發佈的過程。與此同時,也是在系統初始化的時候,Dubbo還會掃描一下當前系統所須要引用的服務,而後向註冊中心請求這些服務所在的IP和端口號。接下來系統就能夠正常運行了。當系統A須要調用系統B的服務的時候,A就會與B創建起一條RPC信道,而後再調用B系統上相應的服務。
這,就是Dubbo的做用。
當咱們使用了微服務架構後,咱們將一個本來完整的系統,按照業務邏輯拆分紅一個個可獨立運行的子系統。爲了下降系統間的耦合度,咱們但願這些子系統可以運行在獨立的環境中,這些環境之間可以相互隔離。
在Docker出現以前,若使用虛擬機來實現運行環境的相互隔離的話成本較高,虛擬機會消耗較多的計算機硬件/軟件資源。Docker不只可以實現運行環境的隔離,並且能極大程度的節約計算機資源,它成爲一種輕量級的「虛擬機」。
當咱們使用微服務架構後,隨着業務的逐漸發展,系統之間的依賴關係會日益複雜,並且各個模塊的構建順序都有所講究。對於一個小型系統來講,也許只有幾個模塊,那麼你每次採用人肉構建的方式也許並不感受麻煩。但隨着系統業務的發展,你的系統之間的依賴關係日益複雜,子系統也逐漸增多,每次構建一下你都要很是當心謹慎,稍有不慎整個服務都沒法正常啓動。並且這些構建的工做很low,但卻須要消耗大量的精力,這無疑下降了開發的效率。不過不要緊,Jenkins就是來幫助你解決這個問題的。
咱們只需在Jenkins中配置好代碼倉庫、各個模塊的構建順序和構建命令,在之後的構建中,只須要點擊「當即構建」按鈕,Jenkins就會自動到你的代碼倉庫中拉取最新的代碼,而後根據你事先配置的構建命令進行構建,最後發佈到指定的容器中運行。你也可讓Jenkins定時檢查代碼倉庫版本的變化,一旦發現變更就自動地開始構建過程,而且讓Jenkins在構建成功後給你發一封郵件。這樣你連「當即構建」的按鈕也不須要按,就能全自動地完成這一切構建過程。
接下來我會帶着你們,以一個在線商城爲例,搭建一套可以自動化部署的微服務框架。這個框架能作以下幾件事情:
本文我以一個你們都很是熟悉的在線商城做爲例子,一步步教你們如何搭建微服務框架,它有以下功能:
注意:本文的IDE使用的是intelliJ IDEA,推薦你們也用這個,用了都說好,用了你就會愛上它。
在動手以前,我先來講一說這一步的目標:
這也是目前主流的項目組織形式,即多模塊項目。
在Gaoxi這個項目下建立各個子模塊,每一個自模塊都是一個獨立的SpringBoot項目:
下面開始動手。
設置groupId、artifactId、version
<groupId>com.gaoxi</groupId> <artifactId>gaoxi</artifactId> <version>0.0.1-SNAPSHOT</version>
目前爲止,模塊之間沒有任何聯繫,下面咱們要經過pom文件來指定它們之間的依賴關係,依賴關係以下圖所示:
Gaoxi-User、Gaoxi-Analysis、Gaoxi-Product、Gaoxi-Order這四個系統至關於以往三層結構的Service層,提供系統的業務邏輯,只不過在微服務結構中,Service層的各個模塊都被抽象成一個個單獨的子系統,它們提供RPC接口供上面的Gaoxi-Controller調用。它們之間的調用由Dubbo來完成,因此它們的pom文件中並不須要做任何配置。而這些模塊和Gaoxi-Common-Service-Facade之間是本地調用,所以須要將Gaoxi-Common-Service-Facade打成jar包,並讓這些模塊依賴這個jar,所以就須要在全部模塊的pom中配置和Gaoxi-Common-Service-Facade的依賴關係。
此外,爲了簡化各個模塊的配置,咱們將全部模塊的通用依賴放在Project的pom文件中,而後讓全部模塊做爲Project的子模塊。這樣子模塊就能夠從父模塊中繼承全部的依賴,而不須要本身再配置了。
下面開始動手:
首先將Common-Service-Facade的打包方式設成jar
當打包這個模塊的時候,Maven會將它打包成jar,並安裝在本地倉庫中。這樣其餘模塊打包的時候就能夠引用這個jar。
<groupId>com.gaoxi</groupId> <artifactId>gaoxi-common-service-facade</artifactId> <version>0.0.1</version> <packaging>jar</packaging>
將其餘模塊的打包方式設爲war
除了Gaoxi-Common-Service-Facade外,其餘模塊都是一個個可獨立運行的子系統,須要在web容器中運行,因此咱們須要將這些模塊的打包方式設成war
<groupId>com.gaoxi</groupId> <artifactId>gaoxi-user</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging>
在總pom中指定子模塊
modules標籤指定了當前模塊的子模塊是誰,可是僅在父模塊的pom文件中指定子模塊還不夠,還須要在子模塊的pom文件中指定父模塊是誰。
<modules> <module>Gaoxi-Analysis</module> <module>Gaoxi-Order</module> <module>Gaoxi-Product</module> <module>Gaoxi-User</module> <module>Gaoxi-Redis</module> <module>Gaoxi-Controller</module> <module>Gaoxi-Common-Service-Facade</module> </modules>
在子模塊中指定父模塊
<parent> <groupId>com.gaoxi</groupId> <artifactId>gaoxi</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent>
到此爲止,模塊的依賴關係配置完畢!但要注意模塊打包的順序。因爲全部模塊都依賴於Gaoxi-Common-Servie-Facade模塊,所以在構建模塊時,首先須要編譯、打包、安裝Gaoxi-Common-Servie-Facade,將它打包進本地倉庫中,這樣上層模塊才能引用到。當該模塊安裝完畢後,再構建上層模塊。不然在構建上層模塊的時候會出現找不到Gaoxi-Common-Servie-Facade中類庫的問題。
<dependencies> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- Spring MVC --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Spring Boot Test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- MyBatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <!-- Mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- Dubbo --> <dependency> <groupId>io.dubbo.springboot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>1.0.0</version> </dependency> <!-- gaoxi-common-service-facade --> <dependency> <groupId>com.gaoxi</groupId> <artifactId>gaoxi-common-service-facade</artifactId> <version>0.0.1</version> </dependency> <!-- AOP --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- guava --> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>23.3-jre</version> </dependency> </dependencies>
當父模塊的pom中配置了公用依賴後,子模塊的pom文件將很是簡潔,以下所示:
<groupId>com.gaoxi</groupId> <artifactId>gaoxi-user</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>gaoxi-user</name> <parent> <groupId>com.gaoxi</groupId> <artifactId>gaoxi</artifactId> <version>0.0.1-SNAPSHOT</version> <relativePath>../pom.xml</relativePath> </parent>
當項目的結構搭建完成以後,接下來你須要配置Docker環境,並將這些項目打包進容器中,驗證下是否能正常啓動。
在使用Docker以前,你固然先要安裝Docker,安裝過程較爲簡單,基本上就是傻瓜式操做,這裏就不做過多介紹了,你能夠在Docker的官網下載相應系統的安裝包。
https://www.docker.com/
在微服務架構中,一個完整的系統被拆分紅了多個被稱爲「微服務」的子系統,這些子系統能夠獨立運行在Web容器中。因此咱們須要爲這些系統提供運行的Web容器,這裏咱們選擇你們較爲熟悉的Tomcat。
咱們知道,Tomcat依賴於Java環境,安裝Tomcat以前要進行一系列環境的配置:安裝Java、配置環境變量、安裝Tomcat等等。這些操做仍是有些繁瑣的。不過不要緊,當使用了Docker以後,這些過程均可以垂手可得地完成。
咱們只需從Docker Hub上找到Tomcat的鏡像資源,而後從上面拉取下來就可使用。你可使用Tomcat官方的鏡像,也可使用我發佈在Docker Hub上的Tomcat鏡像。
注意點:推薦使用個人Tomcat鏡像資源chaimm/tomcat,由於這個鏡像中除了配置Tomcat的安裝環境之外,還有一些本項目中要用到的Jenkins相關的配置。
採用以下命令從Docker Hub上拉取鏡像:
docker pull chaimm/tomcat:1.1
簡單解釋下,docker pull是從從Docker Hub上拉取鏡像的命令,後面的chaimm/tomcat是鏡像的名稱,:1.1是鏡像的版本號。目前這個鏡像的最新版本號是1.1,推薦你們拉取這個。
這裏再簡單介紹下「鏡像」和「容器」的關係。
「鏡像」就比如是面向對象中的「類」,「容器」就比如「類」建立的「對象」。在面向對象中,「類」定義了各類屬性,「類」能夠實例化出多個「對象」;而在Docker中,「鏡像」定義了各類配置信息,它能夠實例化出多個「容器」。「容器」就是一臺能夠運行的「虛擬機」。
接下來咱們須要爲全部的微服務建立各自的容器:
以建立gaoxi-user容器爲例,採用以下命令建立容器:
docker run --name gaoxi-user-1 -p 8082:8080 -v /usr/web/gaoxi-log:/opt/tomcat/gaoxi-log chaimm/tomcat:1.1
-p 8082:8080 表示將容器的8080端口映射到宿主機的8082端口上
這條命令執行成功後,你就能夠經過你的IP:8082
訪問到gaoxi-user-1容器的tomcat了。若是你看到了那隻眼熟了貓,那就說明容器啓動成功了!
接下來,你須要按照上面的方法,給剩下幾個系統建立好Tomcat容器。
注意點:這裏要注意的是,你須要給這些Tomcat容器指定不一樣的端口號,防止端口號衝突。固然,在實際開發中,你並不須要將容器的8080端口映射到宿主機上,這裏僅僅是爲了驗證容器是否啓動成功才這麼作的。
Dubbo一共定義了三種角色,分別是:服務提供者、服務消費者、註冊中心。註冊中心是服務提供者和服務消費者的橋樑,服務消費者會在初始化的時候將本身的IP和端口號發送給註冊中心,而服務消費者經過註冊中心知道服務提供者的IP和端口號。
在Dubbo中,註冊中心有多種選擇,Dubbo最爲推薦的即爲ZooKeeper,本文采用ZooKeepeer做爲Dubbo的註冊中心。
建立ZooKeeper容器也較爲簡單,你們能夠直接使用我建立的ZooKeeper鏡像,經過以下命令便可下載鏡像:
docker pull chaimm/zookeeper-dubbo:1.0
該鏡像中不只運行了一個zookeeper,還運行了一個擁有dubbo-admin項目的tomcat。dubbo-admin是Dubbo的一個可視化管理工具,能夠查看服務的發佈和引用的狀況。
使用以下命令啓動容器:
docker run --name zookeeper-debug -p 2182:2181 -p 10000:8080 chaimm/zookeeper-dubbo:1.0
啓動成功後,你就能夠經過你的IP:10000/dubbo-admin-2.8.4/
訪問到Dubbo-Admin,以下圖所示:
<!-- Spring Boot Dubbo 依賴 --> <dependency> <groupId>io.dubbo.springboot</groupId> <artifactId>spring-boot-starter-dubbo</artifactId> <version>1.0.0</version> </dependency>
假設,咱們須要將Gaoxi-User項目中的UserService發佈成一項RPC服務,供其餘系統遠程調用,那麼咱們究竟該如何藉助Dubbo來實現這一功能呢?
在Gaoxi-Common-Service-Facade中定義UserService的接口
因爲服務的發佈和引用都依賴於接口,但服務的發佈方和引用方在微服務架構中每每不在同一個系統中,因此須要將須要發佈和引用的接口放在公共類庫中,從而雙方都可以引用。接口以下所示:
public interface UserService { public UserEntity login(LoginReq loginReq); }
在Gaoxi-User中定義接口的實現
在實現類上須要加上Dubbo的@Service註解,從而Dubbo會在項目啓動的時候掃描到該註解,將它發佈成一項RPC服務。
@Service(version = "1.0.0") public class UserServiceImpl implements UserService { @Override public UserEntity login(LoginReq loginReq) { // 具體的實現代碼 } }
在Gaoxi-User的application.properties中配置服務提供者的信息
spring.dubbo.application.name=user-provider # 本服務的名稱 spring.dubbo.registry.address=zookeeper://IP:2182 # ZooKeeper所在服務器的IP和端口號 spring.dubbo.protocol.name=dubbo # RPC通訊所採用的協議 spring.dubbo.protocol.port=20883 # 本服務對外暴露的端口號 spring.dubbo.scan=com.gaoxi.user.service # 服務實現類所在的路徑
按照上面配置完成後,當Gaoxi-User系統初始化的時候,就會掃描spring.dubbo.scan所指定的路徑下的@Service註解,該註解標識了須要發佈成RPC服務的類。Dubbo會將這些類的接口信息+本服務器的IP+spring.dubbo.protocol.port所指定的端口號發送給Zookeeper,Zookeeper會將這些信息存儲起來。
這就是服務發佈的過程,下面來看如何引用一項RPC服務。
假設,Gaoxi-Controller須要調用Gaoxi-User 提供的登陸功能,此時它就須要引用UserService這項遠程服務。下面來介紹服務引用的方法。
聲明須要引用的服務
引用服務很是簡單,你只須要在引用的類中聲明一項服務,而後用@Reference標識,以下所示:
@RestController public class UserControllerImpl implements UserController { @Reference(version = "1.0.0") private UserService userService; @Override public Result login(LoginReq loginReq, HttpServletResponse httpRsp) { // 登陸鑑權 UserEntity userEntity = userService.login(loginReq); } }
在Gaoxi-Controller的application.properties中配置服務消費者的信息
spring.dubbo.application.name=controller-consumer # 本服務的名稱 spring.dubbo.registry.address=zookeeper://IP:2182 # zookeeper所在服務器的IP和端口號 spring.dubbo.scan=com.gaoxi # 引用服務的路徑
上述操做完成後,當Gaoxi-Controller初始化的時候,Dubbo就會掃描spring.dubbo.scan所指定的路徑,並找到全部被@Reference修飾的成員變量;而後向Zookeeper請求該服務所在的IP和端口號。當調用userService.login()的時候,Dubbo就會向Gaoxi-User發起請求,完成調用的過程。這個調用過程是一次RPC調用,但做爲程序猿來講,這和調用一個本地函數沒有任何區別,遠程調用的一切都由Dubbo來幫你完成。這就是Dubbo的做用。
Jenkins是一個自動化構建工具,它能夠幫助咱們擺脫繁瑣的部署過程,咱們只須要在一開始配置好構建策略,之後部署只須要一鍵完成。
Jenkins採用Java開發,也須要Java環境,但咱們使用Docker後,一切都採用容器化部署,Jenkins也不例外。
拉取鏡像
這裏咱們使用Jenkins官方提供的鏡像,你們只需執行以下命令拉取便可:
docker pull docker.io/jenkins/jenkins
啓動容器
因爲Jenkins運行在Tomcat容器中,所以咱們將容器的8080端口映射到宿主機的10080端口上:
docker run --name jenkins -p 10080:8080 docker.io/jenkins/jenkins
IP:10080
Jenkins會帶着你進行一系列的初始化設置,你只要跟着它一步步走就好了,比較傻瓜式。接下來咱們要作的是,在Jenkins中爲每個服務建立一個項目,每一個項目中定義了構建的具體流程。因爲咱們將整個項目分紅了6個微服務,因此咱們須要在Jenkins中分別爲這6個服務建立項目。那句開始吧~
OK,Gaoxi-User的構建過程就配置完成了。當咱們點擊「當即構建」按鈕時,Jenkins首先會從咱們指定的Git倉庫中拉取代碼,而後執行Pre Step中的Maven命令,將Gaoxi-Common-Serivce-Facade打包安裝到本地倉庫。而後執行Build過程,將Gaoxi-User進行編譯打包。
但此時Gaoxi-User仍然只是一個本地war包,並無部署到Tomcat容器中,而咱們採用了容器化部署後,Jenkins服務和Gaoxi-User服務並不在同一個Docker容器中,那麼究竟該如何才能將Jenkins本地編譯好的war包發送到Gaoxi-User容器中呢?這就須要使用Jenkins的一個插件——Deploy Plugin。
https://wiki.jenkins.io/displ...
在父項目的pom文件中增長遠程部署插件:
<plugin> <groupId>org.codehaus.cargo</groupId> <artifactId>cargo-maven2-plugin</artifactId> <version>1.6.5</version> <configuration> <container> <!-- 指明使用的tomcat服務器版本 --> <containerId>tomcat8x</containerId> <type>remote</type> </container> <configuration> <type>runtime</type> <cargo.remote.username>Tomcat的用戶名</cargo.remote.username> <cargo.remote.password>Tomcat的密碼</cargo.remote.password> </configuration> </configuration> <executions> <execution> <phase>deploy</phase> <goals> <goal>redeploy</goal> </goals> </execution> </executions> </plugin>
注意:若是你使用了chaimm/tomcat鏡像,那麼其中Tomcat配置都已經完成,默認用戶名:admin、默認密碼:jishimen2019。強烈建議修改用戶名和密碼。
修改Jenkins中gaoxi-user的配置
在「構建後操做」中增長以下配置:
- WAR/EAR files:表示你須要發佈的war包 - Containers:配置目標Tomcat的用戶名和密碼
在實際開發中,咱們的系統每每有多套環境構成,如:開發環境、測試環境、預發環境、生產環境。而不一樣環境的配置各不相同。若是咱們只有一套配置,那麼當系統從一個環境遷移到另外一個環境的時候,就須要經過修改代碼來更換配置,這樣無疑增長了工做的複雜度,並且易於出錯。但好在Maven提供了profile功能,能幫助咱們解決這一個問題。
父項目的pom中添加profile元素
首先,咱們須要在總pom的中添加多套環境的信息,以下所示:
<profiles> <profile> <id>dev</id> <properties> <profileActive>dev</profileActive> </properties> <activation> <activeByDefault>true</activeByDefault> </activation> </profile> <profile> <id>test</id> <properties> <profileActive>test</profileActive> </properties> </profile> <profile> <id>prod</id> <properties> <profileActive>prod</profileActive> </properties> </profile> </profiles>
父項目的pom中添加resource元素
resource標識了不一樣環境下須要打包哪些配置文件。
<resources> <resource> <!-- 標識配置文件所在的目錄 --> <directory>src/main/resources</directory> <filtering>true</filtering> <!-- 構建時將這些配置文件全都排除掉 --> <excludes> <exclude>application.properties</exclude> <exclude>application-dev.properties</exclude> <exclude>application-test.properties</exclude> <exclude>application-prod.properties</exclude> </excludes> </resource> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <!-- 標識構建時所須要的配置文件 --> <includes> <include>application.properties</include> <!-- ${profileActive}這個值會在maven構建時傳入 --> <include>application-${profileActive}.properties</include> </includes> </resource> </resources>
父項目的pom中添加插件maven-resources-plugin
該插件用來在Maven構建時參數替換
<plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> <configuration> <delimiters> <delimiter>@</delimiter> </delimiters> <useDefaultDelimiters>false</useDefaultDelimiters> </configuration> </plugin>
在子項目中建立配置
分別爲dev環境、test環境、prod環境建立三套配置,application.proerpties中存放公用的配置。
spring.profiles.active=@profileActive@
-P test
,在打包的時候-P後面的參數將會做爲@profileActive@的值傳入系統中,從而根據該值打包相應的application-{profileActive}.properties文件。到此爲止,全部準備工做都已經完成,接下來就能夠進入代碼開發階段。下面我以一個例子,帶着你們感覺下有了這套微服務框架後,咱們的開發流程究竟有了哪些改變?下面以開發一個用戶登陸功能爲例,介紹下使用本框架以後開發的流程。
首先須要在Gaoxi-Common-Service-Facade中建立UserService接口,並在其中聲明登陸的抽象函數。
public interface UserService { public UserEntity login(LoginReq loginReq); }
PS:爲何要將UserService放在Gaoxi-Common-Service-Facade中?
在這個項目中,Gaoxi-User是UserService服務的提供方,Gaoxi-Controller是UserService服務的引用方。因爲兩者並不在同一個系統中,因此必需要藉助於Dubbo來實現遠程方法調用。而Dubbo發佈服務和引用服務的時候,都是根據服務的接口標識服務的,即服務引用方和發佈方都須要使用服務的接口,所以須要將服務的接口放在全部項目共同依賴的基礎模塊——Gaoxi-Common-Service-Facade中。
而後在Gaoxi-User中開發UserService的實現——UserServiceImpl。
UserServiceImpl上必需要加上Dubbo的@Service註解,從而告訴Dubbo,在本項目初始化的時候須要將這個類發佈成一項服務,供其餘系統調用。
@Service(version = "1.0.0") @org.springframework.stereotype.Service public class UserServiceImpl implements UserService { @Autowired private UserDAO userDAO; @Override public UserEntity login(LoginReq loginReq) { // 校驗參數 checkParam(loginReq); // 建立用戶查詢請求 UserQueryReq userQueryReq = buildUserQueryReq(loginReq); // 查詢用戶 List<UserEntity> userEntityList = userDAO.findUsers(userQueryReq); // 查詢失敗 if (CollectionUtils.isEmpty(userEntityList)) { throw new CommonBizException(ExpCodeEnum.LOGIN_FAIL); } // 查詢成功 return userEntityList.get(0); } }
當UserService開發完畢後,接下來Gaoxi-Controller須要引用該服務,並向前端提供一個登陸的REST接口。
若要使用userService中的函數,僅須要在userService上添加@Reference註解,而後就像調用本地函數同樣使用userService便可。Dubbo會幫你找到UserService服務所在的IP和端口號,併發送調用請求。但這一切對於程序猿來講是徹底透明的。
@RestController public class UserControllerImpl implements UserController { @Reference(version = "1.0.0") private UserService userService; /** * 登陸 * @param loginReq 登陸請求參數 * @param httpRsp HTTP響應 * @return 登陸是否成功 */ @GetMapping("/login") @Override public Result login(LoginReq loginReq, HttpServletResponse httpRsp) { // 登陸鑑權 UserEntity userEntity = userService.login(loginReq); // 登陸成功 doLoginSuccess(userEntity, httpRsp); return Result.newSuccessResult(); } }
上面的代碼完成後,接下來你須要將代碼提交至你的Git倉庫。接下來就是自動化部署的過程了。
你須要進入Jenkins,因爲剛纔修改了Gaoxi-User和Gaoxi-Controller的代碼,所以你須要分別構建這兩個項目。
接下來Jenkins會自動從你的Git倉庫中拉取最新的代碼,而後依次執行Pre Step、Build、構建後操做的過程。因爲咱們在Pre Step中設置了編譯Gaoxi-Common-Service-Facade,所以Jenkins首先會將其安裝到本地倉庫;而後再執行Build過程,構建Gaoxi-User,並將其打包成war包。最後將執行「構建後操做」,將war包發佈到相應的tomcat容器中。
至此,整個發佈流程完畢!
當Jenkins構建完成後,咱們能夠登陸Dubbo-Admin查看服務發佈和引用的狀態。
當咱們搜索UserService服務後,能夠看到,該服務的提供者已經成功發佈了服務:
點擊「消費者」咱們能夠看到,該服務已經被controller-consumer成功訂閱:
總結一下,這套框架有以下優點: