成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

零基礎都秒懂:手把手教你搭建一套微服務框架!

開發
本文將以原理+實戰的方式,首先對“微服務”相關的概念進行知識點掃盲,然后開始手把手教你搭建一整套微服務系統。

這套微服務框架能干啥?

這套系統搭建完之后,可以實現:

  • 微服務架構,你的整個應用程序將會被拆分成一個個功能獨立的子系統,獨立運行,系統與系統之間通過 RPC 接口通信。

這樣系統之間的耦合度大大降低,你的系統將非常容易擴展,團隊協作效率提升了 N 個檔次。

這種架構通過眼下流行的 Spring Boot 和阿里巴巴吊 Dubbo 框架來實現。

  • 容器化部署,你的各個微服務將采用目前處于浪潮之巔的 Docker 來實現容器化部署,避免一切因環境引起的各種問題,讓你們團隊的全部精力集中在業務開發上。
  • 自動化構建,項目被微服務化后,各個服務之間的關系錯綜復雜,打包構建的工作量相當可怕。不過沒關系,本文將借助 Jenkins,幫助你一鍵自動化部署,從此你便告別了加班。

知識點掃盲篇

咳咳,敲黑板啦!筆記趕緊記起來,課后我要檢查的!檢查不合格的同學放學后留下來!

知識點 1:微服務

微服務一詞近幾年相當火,成為程序猿裝逼熱門詞匯,你不對它有所了解如何在程序猿裝逼圈子里混?下面我用最為通俗易懂的語言介紹它。要講清楚微服務,我先要從一個系統架構的演進過程講起。

單機結構

我想大家最最最熟悉的就是單機結構,一個系統業務量很小的時候所有的代碼都放在一個項目中,然后這個項目部署在一臺服務器上就好了。整個項目所有的服務都由這臺服務器提供。這就是單機結構。

那么,單機結構有啥缺點呢?單機的處理能力畢竟有限,當你的業務增長到一定程度的時候,單機的硬件資源將無法滿足你的業務需求。此時便出現了集群模式。

集群結構

集群模式在程序猿界由各種裝逼解釋,有的讓你根本無法理解,其實就是一個很簡單的玩意兒,且聽我一一道來。

單機處理到達瓶頸的時候,你就把單機復制幾份,這樣就構成了一個“集群”。集群中每臺服務器就叫做這個集群的一個“節點”,所有節點構成了一個集群。

每個節點都提供相同的服務,那么這樣系統的處理能力就相當于提升了好幾倍(有幾個節點就相當于提升了這么多倍)。

但問題是用戶的請求究竟由哪個節點來處理呢?最好能夠讓此時此刻負載較小的節點來處理,這樣使得每個節點的壓力都比較平均。

要實現這個功能,就需要在所有節點之前增加一個“調度者”的角色,用戶的所有請求都先交給它,然后它根據當前所有節點的負載情況,決定將這個請求交給哪個節點處理。這個“調度者”有個牛逼的名字——負載均衡服務器。

集群結構的好處就是系統擴展非常容易。隨著你們系統業務的發展,當前的系統又支撐不住了,那么給這個集群再增加節點就行了。

但是,當你的業務發展到一定程度的時候,你會發現一個問題——無論怎么增加節點,貌似整個集群性能的提升效果并不明顯了。這時候,你就需要使用微服務結構了。

微服務結構

先來對前面的知識點做個總結。從單機結構到集群結構,你的代碼基本無需要作任何修改,你要做的僅僅是多部署幾臺服務器,沒臺服務器上運行相同的代碼就行了。

但是,當你要從集群結構演進到微服務結構的時候,之前的那套代碼就需要發生較大的改動了。

所以對于新系統我們建議,系統設計之初就采用微服務架構,這樣后期運維的成本更低。

但如果一套老系統需要升級成微服務結構的話,那就得對代碼大動干戈了。所以,對于老系統而言,究竟是繼續保持集群模式,還是升級成微服務架構,這需要你們的架構師深思熟慮、權衡投入產出比。

下面開始介紹所謂的微服務。 

微服務就是將一個完整的系統,按照業務功能,拆分成一個個獨立的子系統,在微服務結構中,每個子系統就被稱為“服務”。這些子系統能夠獨立運行在 Web 容器中,它們之間通過 RPC 方式通信。

舉個例子,假設需要開發一個在線商城。按照微服務的思想,我們需要按照功能模塊拆分成多個獨立的服務,如:用戶服務、產品服務、訂單服務、后臺管理服務、數據分析服務等等。

這一個個服務都是一個個獨立的項目,可以獨立運行。如果服務之間有依賴關系,那么通過 RPC 方式調用。

這樣的好處有很多:

  • 系統之間的耦合度大大降低,可以獨立開發、獨立部署、獨立測試,系統與系統之間的邊界非常明確,排錯也變得相當容易,開發效率大大提升。
  • 系統之間的耦合度降低,從而系統更易于擴展。我們可以針對性地擴展某些服務。假設這個商城要搞一次大促,下單量可能會大大提升,因此我們可以針對性地提升訂單系統、產品系統的節點數量,而對于后臺管理系統、數據分析系統而言,節點數量維持原有水平即可。
  • 服務的復用性更高。比如,當我們將用戶系統作為單獨的服務后,該公司所有的產品都可以使用該系統作為用戶系統,無需重復開發。

那么問題來了,當采用微服務結構后,一個完整的系統可能由很多獨立的子系統組成,當業務量漸漸發展起來之后,這些子系統之間的關系將錯綜復雜。

而且為了能夠針對性地增加某些服務的處理能力,某些服務的背后可能是一個集群模式,由多個節點構成,這無疑大大增加了運維的難度。

微服務的想法好是好,但開發、運維的復雜度實在是太高。為了解決這些問題,阿里巴巴的 Dubbo 就橫空出世了。

知識點 2:Dubbo

Dubbo 是一套微服務系統的協調者,在它這套體系中,一共有三種角色:

  • 服務提供者(下面簡稱提供者)
  • 服務消費者(下面簡稱消費者)
  • 注冊中心

你在使用的時候需要將 Dubbo 的 jar 包引入到你的項目中,也就是每個服務都要引入 Dubbo 的 jar 包。

然后當這些服務初始化的時候,Dubbo 就會將當前系統需要發布的服務、以及當前系統的 IP 和端口號發送給注冊中心,注冊中心將其記錄下來。這就是服務發布的過程。

與此同時,也是在系統初始化的時候,Dubbo 還會掃描一下當前系統所需要引用的服務,然后向注冊中心請求這些服務所在的 IP 和端口號。

接下來系統就可以正常運行了。當系統 A 需要調用系統 B 的服務的時候,A 就會與 B 建立起一條 RPC 信道,然后再調用 B 系統上相應的服務。

這,就是 Dubbo 的作用。

知識點 3:容器化部署

當我們使用了微服務架構后,我們將一個原本完整的系統,按照業務邏輯拆分成一個個可獨立運行的子系統。

為了降低系統間的耦合度,我們希望這些子系統能夠運行在獨立的環境中,這些環境之間能夠相互隔離。

在 Docker 出現之前,若使用虛擬機來實現運行環境的相互隔離的話成本較高,虛擬機會消耗較多的計算機硬件/軟件資源。

Docker 不僅能夠實現運行環境的隔離,而且能極大程度的節約計算機資源,它成為一種輕量級的“虛擬機”。

知識點 4:自動化構建

當我們使用微服務架構后,隨著業務的逐漸發展,系統之間的依賴關系會日益復雜,而且各個模塊的構建順序都有所講究。

對于一個小型系統來說,也許只有幾個模塊,那么你每次采用人肉構建的方式也許并不感覺麻煩。

但隨著系統業務的發展,你的系統之間的依賴關系日益復雜,子系統也逐漸增多,每次構建一下你都要非常小心謹慎,稍有不慎整個服務都無法正常啟動。

而且這些構建的工作很 Low,卻需要消耗大量的精力,這無疑降低了開發的效率。不過沒關系,Jenkins 就是來幫助你解決這個問題的。

我們只需在 Jenkins 中配置好代碼倉庫、各個模塊的構建順序和構建命令,在以后的構建中,只需要點擊“立即構建”按鈕,Jenkins 就會自動到你的代碼倉庫中拉取最新的代碼,然后根據你事先配置的構建命令進行構建,最后發布到指定的容器中運行。

你也可以讓 Jenkins 定時檢查代碼倉庫版本的變化,一旦發現變動就自動地開始構建過程,并且讓 Jenkins 在構建成功后給你發一封郵件。這樣你連“立即構建”的按鈕也不需要按,就能全自動地完成這一切構建過程。

實戰動手篇

學習目標

接下來我會帶著大家,以一個在線商城為例,搭建一套能夠自動化部署的微服務框架。

這個框架能做如下幾件事情:

  • 基于 Spring Boot 快速開發,我們將選擇目前熱度很高的 Spring Boot,最大限度地降低配置復雜度,把大量的精力投入到我們的業務開發中來。
  • 基于 Dubbo 的微服務化,我們會使用阿里巴巴的開源框架 Dubbo,將我們的系統拆分成多個獨立的微服務,然后用 Dubbo 來管理所有服務的發布和引用。
  • 有了 Dubbo 之后,調用遠程服務就像調用一個本地函數一樣簡單,Dubbo 會幫我們完成遠程調用背后所需要的一切。
  • 基于 Docker 的容器化部署,由于使用了微服務架構后,我們的系統將會由很多子系統構成。

為了達到多個系統之間環境隔離的目的,我們可以將它們部署在多臺服務器上,可這樣的成本會比較高,而且每臺服務器的性能可能都沒有充分利用起來。

所以我們很自然地想到了虛擬機,在同一臺服務器上運行多個虛擬機,從而實現環境的隔離,每個虛擬機上運行獨立的服務。然而虛擬機的隔離成本依舊很高,因為它需要占用服務器較多的硬件資源和軟件資源。

所以,在微服務結構下,要實現服務環境的隔離,Docker 是最佳選擇。它比虛擬機更加輕量級,占用資源較少,而且能夠實現快速部署。

基于 Jenkins 的自動化構建,當我們采用了微服務架構后,我們會發現這樣一個問題。整個系統由許許多多的服務構成,這些服務都需要運行在單獨的容器中,那么每次發布的復雜度將非常高。

首先你要搞清楚這些服務之間的依賴關系、啟動的先后順序,然后再將多個子系統挨個編譯、打包、發布。這些操作技術難度低,卻又容易出錯。

那么有什么工具能夠幫助我們解決這些問題呢?答案就是——Jenkins。 它是一款自動化構建的工具,簡單的來說,就是我們只需要在它的界面上按一個按鈕,就可以實現上述一系列復雜的過程。

項目背景介紹

本文我以一個在線商城作為例子,一步步教大家如何搭建微服務框架,它有如下功能:

  • 產品管理,產品的增刪改查。
  • 訂單管理,訂單的增刪改查、購物車功能。
  • 用戶管理,用戶的登錄、注冊、權限管理、收貨地址等等。
  • 數據分析,提供對本系統數據分析的功能。

注意:本文的 IDE 使用的是 intelliJ IDEA,推薦大家也用這個,用了都說好,用了你就會愛上它。

創建項目的組織結構

在動手之前,我先來說一說這一步的目標:

  • 創建一個 Maven Project,命名為“Gaoxi”。這個 Project 由多個 Module 構成,每個 Module 對應著“微服務”的一個子系統,可獨立運行,是一個獨立的項目。 這也是目前主流的項目組織形式,即多模塊項目。
  • 在 Gaoxi 這個項目下創建各個子模塊。

每個自模塊都是一個獨立的 Spring Boot 項目:

  • Gaoxi-User,用戶服務。
  • Gaoxi-Order,訂單服務。
  • Gaoxi-Product,產品服務。
  • Gaoxi-Analysis,數據分析服務。
  • Gaoxi-Controller,本系統的控制層,和以往三層結構中的 Controller 層的作用一樣,都是用作請求調度,只不過在微服務架構中,我們將它抽象成一個單獨的系統,可以獨立運行。
  • Gaoxi-Common-Service-Facade,它處于本系統的最底層,被所有模塊依賴,一些公用的類庫都放在這里。
  • Gaoxi-Redis,我們將 Redis 封裝成一個單獨的服務,運行在獨立的容器中,當哪一個模塊需要使用 Redis 的時候,僅需要引入該服務即可,就免去了各種繁瑣的、重復的配置。而這些配置均在 Gaoxi-Redis 系統中完成了。

下面開始動手。

創建 Project

首先 New 一個 Project,如下圖:

然后選擇 Spring Initializr,如下圖所示:

設置 groupId、artifactId、version,代碼如下: 

  1. <groupId>com.gaoxi</groupId>  
  2. <artifactId>gaoxi</artifactId>  
  3. <version>0.0.1-SNAPSHOT</version> 

Project 創建完畢!接下來在 Project 下面創建 Module。

創建 Module

在 Project 上 New Module,如下圖:

和剛才一樣,選擇 Spring Initializr,設置 groupId、artifactId、version。

依次創建好所有的 Module,如下圖所示:

構建模塊的依賴關系

目前為止,模塊之間沒有任何聯系,下面我們要通過 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。 

  1. <groupId>com.gaoxi</groupId>  
  2. <artifactId>gaoxi-common-service-facade</artifactId>  
  3. <version>0.0.1</version>  
  4. <packaging>jar</packaging> 

將其他模塊的打包方式設為 war。除了 Gaoxi-Common-Service-Facade 外,其他模塊都是一個個可獨立運行的子系統,需要在 Web 容器中運行,所以我們需要將這些模塊的打包方式設成 war。 

  1. <groupId>com.gaoxi</groupId>  
  2. <artifactId>gaoxi-user</artifactId>  
  3. <version>0.0.1-SNAPSHOT</version>  
  4. <packaging>war</packaging> 

在總 pom 中指定子模塊。modules 標簽指定了當前模塊的子模塊是誰,但是僅在父模塊的 pom 文件中指定子模塊還不夠,還需要在子模塊的 pom 文件中指定父模塊是誰。 

  1. <modules>  
  2.     <module>Gaoxi-Analysis</module>  
  3.     <module>Gaoxi-Order</module>  
  4.     <module>Gaoxi-Product</module>  
  5.     <module>Gaoxi-User</module>  
  6.     <module>Gaoxi-Redis</module>  
  7.     <module>Gaoxi-Controller</module>  
  8.     <module>Gaoxi-Common-Service-Facade</module>  
  9. </modules> 

在子模塊中指定父模塊。 

  1. <parent>  
  2.     <groupId>com.gaoxi</groupId>  
  3.     <artifactId>gaoxi</artifactId>  
  4.     <version>0.0.1-SNAPSHOT</version>  
  5.     <relativePath>../pom.xml</relativePath>  
  6. </parent> 

到此為止,模塊的依賴關系配置完畢!但要注意模塊打包的順序。

由于所有模塊都依賴于 Gaoxi-Common-Servie-Facade 模塊,因此在構建模塊時,首先需要編譯、打包、安裝 Gaoxi-Common-Servie-Facade,將它打包進本地倉庫中,這樣上層模塊才能引用到。當該模塊安裝完畢后,再構建上層模塊。

否則在構建上層模塊的時候會出現找不到 Gaoxi-Common-Servie-Facade 中類庫的問題。

在父模塊的 pom 中添加所有子模塊公用的依賴 

  1. <dependencies>  
  2.     <!-- Spring Boot -->  
  3.     <dependency>  
  4.         <groupId>org.springframework.boot</groupId>  
  5.         <artifactId>spring-boot-starter</artifactId>  
  6.     </dependency>  
  7.     <!-- Spring MVC -->  
  8.     <dependency>  
  9.         <groupId>org.springframework.boot</groupId>  
  10.         <artifactId>spring-boot-starter-web</artifactId>  
  11.     </dependency>  
  12.     <!-- Spring Boot Test -->  
  13.     <dependency>  
  14.         <groupId>org.springframework.boot</groupId>  
  15.         <artifactId>spring-boot-starter-test</artifactId>  
  16.         <scope>test</scope>  
  17.     </dependency>  
  18.     <!-- MyBatis -->  
  19.     <dependency>  
  20.         <groupId>org.mybatis.spring.boot</groupId>  
  21.         <artifactId>mybatis-spring-boot-starter</artifactId>  
  22.         <version>1.3.1</version>  
  23.     </dependency>  
  24.     <!-- Mysql -->  
  25.     <dependency>  
  26.         <groupId>mysql</groupId>  
  27.         <artifactId>mysql-connector-java</artifactId>  
  28.         <scope>runtime</scope>  
  29.     </dependency>  
  30.     <!-- Dubbo -->  
  31.     <dependency> 
  32.          <groupId>io.dubbo.springboot</groupId>  
  33.         <artifactId>spring-boot-starter-dubbo</artifactId>  
  34.         <version>1.0.0</version>  
  35.     </dependency>  
  36.     <!-- gaoxi-common-service-facade -->  
  37.     <dependency>  
  38.         <groupId>com.gaoxi</groupId>  
  39.         <artifactId>gaoxi-common-service-facade</artifactId>  
  40.         <version>0.0.1</version>  
  41.     </dependency>  
  42.     <!-- AOP -->  
  43.     <dependency>  
  44.         <groupId>org.springframework.boot</groupId>  
  45.         <artifactId>spring-boot-starter-aop</artifactId>  
  46.     </dependency>  
  47.     <!-- guava -->  
  48.     <dependency>  
  49.         <groupId>com.google.guava</groupId>  
  50.         <artifactId>guava</artifactId>  
  51.         <version>23.3-jre</version>  
  52.     </dependency>  
  53. </dependencies> 

當父模塊的 pom 中配置了公用依賴后,子模塊的 pom 文件將非常簡潔,如下所示: 

  1. <groupId>com.gaoxi</groupId>  
  2. <artifactId>gaoxi-user</artifactId>  
  3. <version>0.0.1-SNAPSHOT</version>  
  4. <packaging>war</packaging>  
  5. <name>gaoxi-user</name 
  6. <parent>  
  7.     <groupId>com.gaoxi</groupId>  
  8.     <artifactId>gaoxi</artifactId>  
  9.     <version>0.0.1-SNAPSHOT</version>  
  10.     <relativePath>../pom.xml</relativePath>  
  11. </parent> 

當項目的結構搭建完成之后,接下來你需要配置 Docker 環境,并將這些項目打包進容器中,驗證下是否能正常啟動。

創建 Docker 容器

安裝 Docker

在使用 Docker 之前,你當然先要安裝 Docker,安裝過程較為簡單,基本上就是傻瓜式操作,這里就不作過多介紹了,你可以在 Docker 的官網下載相應系統的安裝包。

獲取 Tomcat 鏡像

在微服務架構中,一個完整的系統被拆分成了多個被稱為“微服務”的子系統,這些子系統可以獨立運行在 Web 容器中。所以我們需要為這些系統提供運行的 Web 容器,這里我們選擇大家較為熟悉的 Tomcat。

我們知道,Tomcat 依賴于 Java 環境,安裝 Tomcat 之前要進行一系列環境的配置:安裝 Java、配置環境變量、安裝 Tomcat 等等。

這些操作還是有些繁瑣的。不過沒關系,當使用了 Docker 之后,這些過程都可以輕而易舉地完成。

我們只需從 Docker Hub 上找到 Tomcat 的鏡像資源,然后從上面拉取下來就可以使用。你可以使用 Tomcat 官方的鏡像,也可以使用我發布在 Docker Hub 上的 Tomcat 鏡像。

注意點:推薦使用我的 Tomcat 鏡像資源 chaimm/tomcat,因為這個鏡像中除了配置 Tomcat 的安裝環境以外,還有一些本項目中要用到的 Jenkins 相關的配置。

采用如下命令從 Docker Hub 上拉取鏡像: 

  1. docker pull chaimm/tomcat:1.1 

簡單解釋下,Docker pull 是從 Docker Hub 上拉取鏡像的命令,后面的 chaimm/tomcat 是鏡像的名稱;:1.1 是鏡像的版本號。目前這個鏡像的最新版本號是 1.1,推薦大家拉取這個。

創建 Tomcat 容器

這里再簡單介紹下“鏡像”和“容器”的關系。 “鏡像”就好比是面向對象中的“類”,“容器”就好比“類”創建的“對象”。

在面向對象中,“類”定義了各種屬性,“類”可以實例化出多個“對象”;而在 Docker 中,“鏡像”定義了各種配置信息,它可以實例化出多個“容器”。“容器”就是一臺可以運行的“虛擬機”。

接下來我們需要為所有的微服務創建各自的容器:

  • gaoxi-user
  • gaoxi-product
  • gaoxi-order
  • gaoxi-analysis
  • gaoxi-controller
  • gaoxi-redis

以創建 gaoxi-user 容器為例,采用如下命令創建容器: 

  1. docker run --name gaoxi-user-1 -p 8082:8080 -v /usr/web/gaoxi-log:/opt/tomcat/gaoxi-log chaimm/tomcat:1.1 
  • --name:指定容器的名字。
  • -p:指定容器的端口映射,-p 8082:8080 表示將容器的 8080 端口映射到宿主機的 8082 端口上。
  • -v:指定容器數據卷的映射,xxx:yyy 表示將容器 yyy 目錄映射到宿主機的 xxx 目錄上,從而訪問宿主機的 xxx 目錄就相當于訪問容器的 yyy 目錄。
  • chaimm/tomcat:1.1:表示容器所對應的鏡像。

這條命令執行成功后,你就可以通過你的 IP:8082 訪問到 gaoxi-user-1 容器的 Tomcat 了。如果你看到了那只眼熟的貓,那就說明容器啟動成功了!

接下來,你需要按照上面的方法,給剩下幾個系統創建好 Tomcat 容器。

注意點:你需要給這些 Tomcat 容器指定不同的端口號,防止端口號沖突。當然,在實際開發中,你并不需要將容器的 8080 端口映射到宿主機上,這里僅僅是為了驗證容器是否啟動成功才這么做的。

整合 Dubbo

創建 ZooKeeper 容器

Dubbo 一共定義了三種角色,分別是:服務提供者、服務消費者、注冊中心。

注冊中心是服務提供者和服務消費者的橋梁,服務消費者會在初始化的時候將自己的 IP 和端口號發送給注冊中心,而服務消費者通過注冊中心指導服務提供者的 IP 和端口號。

在 Dubbo 中,注冊中心有多種選擇,Dubbo 最為推薦的即為 ZooKeeper,本文采用 ZooKeepeer 作為 Dubbo 的注冊中心。

創建 ZooKeeper 容器也較為簡單,大家可以直接使用我創建的 ZooKeeper 鏡像,通過如下命令即可下載鏡像: 

  1. docker pull chaimm/zookeeper-dubbo:1.0 

該鏡像中不僅運行了一個 ZooKeeper,還運行了一個擁有 Dubbo-Admin 項目的 Tomcat。dubbo-admin 是 Dubbo 的一個可視化管理工具,可以查看服務的發布和引用的情況。

使用如下命令啟動容器: 

  1. docker run --name zookeeper-debug -p 2182:2181 -p 10000:8080 chaimm/zookeeper-dubbo:1.0 
  • -p 2182:2181,將容器的 2181 端口映射到宿主機的 2182 端口上,該端口是 ZooKeeper 的端口號。
  • -p 10000:8080,將容器的 8080 端口映射到宿主機的 10000 端口上,該端口是 Dubbo-Admin 所在 Tomcat 的端口號。

啟動成功后,你就可以通過你的 IP:10000/dubbo-admin-2.8.4/ 訪問到 Dubbo-Admin,如下圖所示:

父 POM 文件中引入 Dubbo 依賴 

  1. <!-- Spring Boot Dubbo 依賴 -->  
  2. <dependency>  
  3.     <groupId>io.dubbo.springboot</groupId>  
  4.     <artifactId>spring-boot-starter-dubbo</artifactId>  
  5.     <version>1.0.0</version>  
  6. </dependency> 

發布服務

假設,我們需要將 Gaoxi-User 項目中的 UserService 發布成一項 RPC 服務,供其他系統遠程調用,那么我們究竟該如何借助 Dubbo 來實現這一功能呢?

在 Gaoxi-Common-Service-Facade 中定義 UserService 的接口。

由于服務的發布和引用都依賴于接口,但服務的發布方和引用方在微服務架構中往往不在同一個系統中,所以需要將發布和引用的接口放在公共類庫中,從而雙方都能夠引用。

接口如下所示: 

  1. public interface UserService {  
  2.     public UserEntity login(LoginReq loginReq);  

在 Gaoxi-User 中定義接口的實現。在實現類上需要加上 Dubbo 的 @Service 注解,從而 Dubbo 會在項目啟動的時候掃描到該注解,將它發布成一項 RPC 服務。 

  1. @Service(version = "1.0.0" 
  2. public class UserServiceImpl implements UserService {  
  3.     @Override  
  4.     public UserEntity login(LoginReq loginReq) {  
  5.         // 具體的實現代碼  
  6.     }  

在 Gaoxi-User 的 application.properties 中配置服務提供者的信息。 

  1. spring.dubbo.application.name=user-provider # 本服務的名稱  
  2. spring.dubbo.registry.address=zookeeper://IP:2182 # ZooKeeper所在服務器的IP和端口號  
  3. spring.dubbo.protocol.name=dubbo # RPC通信所采用的協議  
  4. spring.dubbo.protocol.port=20883 # 本服務對外暴露的端口號  
  5. 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 標識,如下所示: 

  1. @RestController  
  2. public class UserControllerImpl implements UserController {  
  3.     @Reference(version = "1.0.0" 
  4.     private UserService userService;  
  5.     @Override  
  6.     public Result login(LoginReq loginReq, HttpServletResponse httpRsp) {  
  7.         // 登錄鑒權  
  8.         UserEntity userEntity = userService.login(loginReq);  
  9.     }  

在 Gaoxi-Controller 的 application.properties 中配置服務消費者的信息。 

  1. spring.dubbo.application.name=controller-consumer # 本服務的名稱  
  2. spring.dubbo.registry.address=zookeeper://IP:2182 # zookeeper所在服務器的IP和端口號  
  3. spring.dubbo.scan=com.gaoxi # 引用服務的路徑 

上述操作完成后,當 Gaoxi-Controller 初始化的時候,Dubbo 就會掃描 spring.dubbo.scan 所指定的路徑,并找到所有被 @Reference 修飾的成員變量;然后向 Zookeeper 請求該服務所在的 IP 和端口號。

當調用 userService.login() 的時候,Dubbo 就會向 Gaoxi-User 發起請求,完成調用的過程。

這個調用過程是一次 RPC 調用,但作為程序猿來說,這和調用一個本地函數沒有任何區別,遠程調用的一切都由 Dubbo 來幫你完成。這就是 Dubbo 的作用。

自動化構建

Jenkins 是一個自動化構建工具,它可以幫助我們擺脫繁瑣的部署過程,我們只需要在一開始配置好構建策略,以后部署只需要一鍵完成。

創建 Jenkins 容器

Jenkins 采用 Java 開發,也需要 Java 環境,但我們使用 Docker 后,一切都采用容器化部署,Jenkins 也不例外。

拉取鏡像,這里我們使用 Jenkins 官方提供的鏡像,大家只需執行如下命令拉取即可: 

  1. docker pull docker.io/jenkins/jenkins 

啟動容器,由于 Jenkins 運行在 Tomcat 容器中,因此我們將容器的 8080 端口映射到宿主機的 10080 端口上: 

  1. docker run --name jenkins -p 10080:8080 docker.io/jenkins/jenkins 

初始化 Jenkins,然后你需要訪問 IP:10080,Jenkins 會帶著你進行一系列的初始化設置,你只要跟著它一步步走就行了,比較傻瓜式。

在 Jenkins 中創建項目

接下來我們要做的是,在 Jenkins 中為每一個服務創建一個項目,每個項目中定義了構建的具體流程。由于我們將整個項目分成了 6 個微服務,所以我們需要在 Jenkins 中分別為這 6 個服務創建項目。那就開始吧~

點擊頁面左側的“新建”按鈕:

輸入項目名稱 gaoxi-user,選擇“構建一個 Maven 項目”,然后點擊“OK”:

配置 Git 倉庫,選擇 Git,然后輸入本項目 Git 倉庫的 URL,并在 Credentials 中輸入 Git 的用戶名和密碼,如下圖所示:

構建觸發器,選擇第一項,如下圖所示:

Pre Step,Pre Step 會在正式構建前執行,由于所有項目都依賴于 Gaoxi-Common-Service—Facade,因此在項目構建前,需要將它安裝到本地倉庫,然后才能被當前項目正確依賴。 

因此,在 Pre Step 中填寫如下信息:

Build,然后就是正式構建的過程,填寫如下信息即可:

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。

遠程部署

首先你需要下載 Deploy Plugin 插件。

下載地址:https://wiki.jenkins.io/display/JENKINS/Deploy+Plugin

安裝插件,在系統管理–>插件管理–>高級上傳 deploy.hpi 進行安裝。

在父項目的 pom 文件中增加遠程部署插件: 

  1. <plugin>  
  2.     <groupId>org.codehaus.cargo</groupId>  
  3.     <artifactId>cargo-maven2-plugin</artifactId>  
  4.     <version>1.6.5</version>  
  5.     <configuration>  
  6.         <container>  
  7.             <!-- 指明使用的tomcat服務器版本 -->  
  8.             <containerId>tomcat8x</containerId>  
  9.             <type>remote</type>  
  10.         </container>  
  11.         <configuration>  
  12.             <type>runtime</type>  
  13.             <cargo.remote.username>Tomcat的用戶名</cargo.remote.username>  
  14.             <cargo.remote.password>Tomcat的密碼</cargo.remote.password 
  15.         </configuration>  
  16.     </configuration>  
  17.     <executions>  
  18.         <execution>  
  19.             <phase>deploy</phase>  
  20.             <goals>  
  21.                 <goal>redeploy</goal>  
  22.             </goals>  
  23.         </execution>  
  24.     </executions>  
  25. </plugin> 

為 Tomcat 設置用戶名和密碼,修改 gaoxi-user 容器中 Tomcat 的 tomcat-users.xml 文件,增加 Tomcat 的 manager 用戶。

注意:如果你使用了 chaimm/tomcat 鏡像,那么其中 Tomcat 配置都已經完成,默認用戶名:admin、默認密碼:jishimen2019。強烈建議修改用戶名和密碼。

修改 Jenkins 中 gaoxi-user 的配置,在“構建后操作”中增加如下配置:

  • WAR/EAR files:表示你需要發布的 war 包。
  • Containers:配置目標 Tomcat 的用戶名和密碼。

Maven 的 profile 功能

在實際開發中,我們的系統往往有多套環境構成,如:開發環境、測試環境、預發環境、生產環境。而不同環境的配置各不相同。

如果我們只有一套配置,那么當系統從一個環境遷移到另一個環境的時候,就需要通過修改代碼來更換配置,這樣無疑增加了工作的復雜度,而且易于出錯。但好在 Maven 提供了 profile 功能,能幫助我們解決這一個問題。

父項目的 pom 中添加 profile 元素,首先,我們需要在總 pom 的中添加多套環境的信息,如下所示: 

  1. <profiles>  
  2.     <profile>  
  3.         <id>dev</id>  
  4.         <properties>  
  5.             <profileActive>dev</profileActive>  
  6.         </properties>  
  7.         <activation>  
  8.             <activeByDefault>true</activeByDefault>  
  9.         </activation>  
  10.     </profile>  
  11.     <profile>  
  12.         <id>test</id>  
  13.         <properties>  
  14.             <profileActive>test</profileActive>  
  15.         </properties>  
  16.     </profile>  
  17.     <profile>  
  18.         <id>prod</id>  
  19.         <properties>  
  20.             <profileActive>prod</profileActive>  
  21.         </properties>  
  22.     </profile>  
  23. </profiles> 

父項目的 pom 中添加 resource 元素,resource 標識了不同環境下需要打包哪些配置文件。 

  1. <resources>  
  2.     <resource>  
  3.         <!-- 標識配置文件所在的目錄 -->  
  4.         <directory>src/main/resources</directory>  
  5.         <filtering>true</filtering>  
  6.         <!-- 構建時將這些配置文件全都排除掉 -->  
  7.         <excludes>  
  8.             <exclude>application.properties</exclude>  
  9.             <exclude>application-dev.properties</exclude>  
  10.             <exclude>application-test.properties</exclude>  
  11.             <exclude>application-prod.properties</exclude>  
  12.         </excludes>  
  13.     </resource>  
  14.     <resource>  
  15.         <directory>src/main/resources</directory>  
  16.         <filtering>true</filtering>  
  17.         <!-- 標識構建時所需要的配置文件 -->  
  18.         <includes>  
  19.             <include>application.properties</include>  
  20.             <!-- ${profileActive}這個值會在maven構建時傳入 -->  
  21.             <include>application-${profileActive}.properties</include>  
  22.         </includes>  
  23.     </resource>  
  24. </resources> 

父項目的 pom 中添加插件 maven-resources-plugin,該插件用來在 Maven 構建時參數替換。 

  1. <plugin>  
  2.     <artifactId>maven-resources-plugin</artifactId>  
  3.     <version>3.0.2</version>  
  4.     <configuration>  
  5.         <delimiters>  
  6.             <delimiter>@</delimiter>  
  7.         </delimiters>  
  8.         <useDefaultDelimiters>false</useDefaultDelimiters>  
  9.     </configuration>  
  10. </plugin> 

在子項目中創建配置,分別為 dev 環境、test 環境、prod 環境創建三套配置,application.proerpties 中存放公用的配置。

在 application.properties 中添加spring.profiles.active=@profileActive@: 

  1. spring.profiles.active=@profileActive@  

修改 Jenkins 的配置,在所有 Jenkins 中所有 Maven 命令的末尾添加-P test,在打包的時候 -P 后面的參數將會作為 @profileActive@ 的值傳入系統中,從而根據該值打包相應的 application-{profileActive}.properties 文件。

開發流程

到此為止,所有準備工作都已經完成,接下來就可以進入代碼開發階段。下面我以一個例子,帶著大家感受下有了這套微服務框架后,我們的開發流程究竟有了哪些改變?

下面以開發一個用戶登錄功能為例,介紹下使用本框架之后開發的流程。

開發目標

有如下兩個開發目標:

  • 在 Gaoxi-User 系統中實現登錄的業務邏輯,并發布成 RPC 服務。
  • 在 Gaoxi-Controller 中遠程調用登錄服務,并向前端提供登錄的 REST 接口。

開發登錄服務

首先需要在 Gaoxi-Common-Service-Facade 中創建 UserService 接口,并在其中聲明登錄的抽象函數。 

  1. public interface UserService {  
  2.     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,在本項目初始化的時候需要將這個類發布成一項服務,供其他系統調用。 

  1. @Service(version = "1.0.0" 
  2. @org.springframework.stereotype.Service  
  3. public class UserServiceImpl implements UserService {  
  4.     @Autowired  
  5.     private UserDAO userDAO;  
  6.     @Override  
  7.     public UserEntity login(LoginReq loginReq) {  
  8.         // 校驗參數  
  9.         checkParam(loginReq);  
  10.         // 創建用戶查詢請求  
  11.         UserQueryReq userQueryReq = buildUserQueryReq(loginReq);  
  12.         // 查詢用戶  
  13.         List<UserEntity> userEntityList = userDAO.findUsers(userQueryReq);  
  14.         // 查詢失敗  
  15.         if (CollectionUtils.isEmpty(userEntityList)) {  
  16.             throw new CommonBizException(ExpCodeEnum.LOGIN_FAIL);  
  17.         }  
  18.         // 查詢成功  
  19.         return userEntityList.get(0);  
  20.     }  

引用登錄服務

當 UserService 開發完畢后,接下來 Gaoxi-Controller 需要引用該服務,并向前端提供一個登錄的 REST 接口。

若要使用 userService 中的函數,僅需要在 userService 上添加 @Reference 注解,然后就像調用本地函數一樣使用 userService 即可。

Dubbo 會幫你找到 UserService 服務所在的 IP 和端口號,并發送調用請求。但這一切對于程序猿來說是完全透明的。 

  1. @RestController  
  2. public class UserControllerImpl implements UserController {  
  3.     @Reference(version = "1.0.0" 
  4.     private UserService userService;  
  5.     @Override  
  6.     public Result login(LoginReq loginReq, HttpServletResponse httpRsp) {  
  7.         // 登錄鑒權  
  8.         UserEntity userEntity = userService.login(loginReq);  
  9.         // 登錄成功  
  10.         doLoginSuccess(userEntity, httpRsp);  
  11.         return Result.newSuccessResult();  
  12.     }  

自動構建服務

上面的代碼完成后,你需要將代碼提交至你的 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 成功訂閱:

總結

總結一下,這套框架有如下優勢:

  • 微服務架構,我們借助于 Spring Boot 和 Dubbo 實現了微服務架構。微服務架構的理念就是將一個原本龐大、復雜的系統,按照業務功能拆分成一個個具有獨立功能、可以獨立運行的子系統。

系統之間若有依賴,則通過 RPC 接口通信。從而最大限度地降低了系統之間的耦合度,從而更加易于擴展、更加易于維護。

  • 容器化部署,我們借助于 Docker 實現了容器化部署。容器能夠幫助我們屏蔽不同環境下的配置問題,使得我們只需要有一個 Dockerfile 文件,就可以處處運行。

和虛擬機一樣,Docker 也擁有環境隔離的能力,但比虛擬機更加輕量級,由于每個容器僅僅是一條進程,因此它可以達到秒級的啟動速度。

  • 自動化構建,我們借助于 Jenkins 實現了所有項目的自動化構建與部署。我們只需要點擊“立即構建”這個按鈕,Jenkins 就可以幫助我們梳理好錯綜復雜的項目依賴關系,準確無誤地完成構建,并將 war 包發送到相應的 Web 容器中。

在啟動的過程中,Dubbo 會掃描當前項目所需要發布和引用的服務,將所需要發布的服務發布到 ZooKeeper 上,并向 ZooKeeper 訂閱所需的服務。

有了 Jenkins 之后,這一切都是自動化完成。也許你并沒有太強烈地感受到 Jenkins 所帶來的便利。但是你想一想,對于一個具有錯綜復雜的依賴關系的微服務系統而言,如果每個服務的構建都需要你手動完成的話,你很快就會崩潰,你大把的時間將會投入在無聊但又容易出錯的服務構建上,而 Jenkins 的出現能讓這一切自動化完成。

作者:大閑人柴毛毛

編輯:陶家龍、孫淑娟

來源:轉載自公眾號:大閑人柴毛毛,ID:dxrcmm

源碼:https://github.com/bz51/SpringBoot-Dubbo-Docker-Jenkins


 

責任編輯:龐桂玉 來源: 51CTO技術棧
相關推薦

2022-08-25 14:41:51

集群搭建

2024-10-21 08:01:49

私服倉庫Maven

2019-08-26 09:25:23

RedisJavaLinux

2020-06-17 07:35:57

虛擬機部署微服務

2022-07-14 07:34:26

windowsmysqlcentos

2017-01-18 09:04:13

TensorFlow圖像識別

2022-03-14 14:47:21

HarmonyOS操作系統鴻蒙

2010-01-20 10:44:01

linux DHCP服務器

2017-01-18 09:20:23

TensorFlow圖像識別

2011-03-25 12:45:49

Oracle SOA

2020-11-03 14:10:29

Vue服務端渲染前端

2023-03-14 07:34:47

代碼生成器開發

2010-07-06 09:43:57

搭建私有云

2010-07-06 09:38:51

搭建私有云

2022-01-04 08:52:14

博客網站Linux 系統開源

2021-07-14 09:00:00

JavaFX開發應用

2011-01-10 14:41:26

2011-05-03 15:59:00

黑盒打印機

2025-05-07 00:31:30

2010-10-29 14:04:49

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 不卡视频在线 | 精品啪啪| 毛片一区二区 | 久久久成人精品 | 国产欧美精品一区二区三区 | 网站一区二区三区 | 亚洲www | 亚洲精品久久久蜜桃网站 | 免费一区二区 | 久久99精品久久久久久 | 九九精品久久久 | 久久亚洲国产精品日日av夜夜 | 在线观看免费观看在线91 | 91精品国产手机 | 99精品视频免费观看 | 日日噜噜夜夜爽爽狠狠 | 亚洲精品白浆高清久久久久久 | 欧美成人精品二区三区99精品 | 在线免费国产视频 | 国产精品美女www爽爽爽视频 | 日韩在线播放视频 | 黄色大片免费观看 | 91精品国产综合久久久久 | 日日日干干干 | 久久精品国产久精国产 | 日韩视频一区 | 日韩视频一区二区在线 | 亚洲高清视频在线观看 | 成人福利网站 | 成人3d动漫一区二区三区91 | 中文字幕在线欧美 | 另类专区亚洲 | 亚洲国产欧美在线人成 | 男女羞羞视频在线观看 | 欧美日韩国产三级 | 精品美女视频在免费观看 | 日韩精品极品视频在线观看免费 | 国产精品久久久久久久久久 | 日本免费在线观看视频 | 国产日产精品一区二区三区四区 | 中文字幕 亚洲一区 |