微服務架構 - 快速指南



微服務架構 - 簡介

微服務是一種基於服務的應用程式開發方法。在這種方法中,大型應用程式將被分解成最小的獨立服務單元。微服務是透過將整個應用程式劃分為相互連線的服務集合來實現面向服務架構 (SOA) 的過程,其中每個服務只滿足一個業務需求。

走向微服務的概念

在面向服務架構中,整個軟體包將被細分為小型、相互連線的業務單元。這些小型業務單元中的每一個都將使用不同的協議相互通訊,以向客戶端提供成功的業務。現在問題是,微服務架構 (MSA) 與 SOA 有何不同?簡單來說,SOA 是一種設計模式,而微服務是實現 SOA 的一種實現方法,或者我們可以說微服務是 SOA 的一種型別。

以下是在開發面向微服務的應用程式時需要牢記的一些規則。

  • 獨立性 - 每個微服務都應該可以獨立部署。

  • 耦合性 - 所有微服務都應該彼此鬆散耦合,以便一個服務的更改不會影響其他服務。

  • 業務目標 - 整個應用程式的每個服務單元都應該是最小的,並且能夠實現一個特定的業務目標。

讓我們以線上購物門戶為例來深入瞭解微服務。現在,讓我們將整個電子商務入口網站分解成小型業務單元,例如使用者管理、訂單管理、結賬、支付管理、配送管理等。一個成功的訂單需要在特定時間範圍內透過所有這些模組。以下是與一個電子商務系統相關的不同業務單元的綜合影像。

Electronic Commerce Solutions

這些業務模組中的每一個都應該有自己的業務邏輯和利益相關者。它們為了某些特定需求與其他第三方供應商軟體通訊,也彼此通訊。例如,訂單管理可能會與使用者管理通訊以獲取使用者資訊。

現在,假設您正在執行一個包含前面提到的所有這些業務單元的線上購物門戶,您確實需要一個包含不同層(例如前端、後端、資料庫等)的企業級應用程式。如果您的應用程式沒有擴充套件並且完全在一個 WAR 檔案中開發,那麼它將被稱為典型的單體應用程式。根據 IBM 的說法,一個典型的單體應用程式在內部應該具有以下模組結構,其中只有一個端點或應用程式負責處理所有使用者請求。

Database

在上圖中,您可以看到不同的模組,例如用於儲存不同使用者和業務資料的資料庫。在前端,我們有不同的裝置,我們通常在這些裝置上呈現使用者或業務資料以供使用。在中間,我們有一個包,它可以是可部署的 EAR 或 WAR 檔案,該檔案接收來自使用者端的請求,在資源的幫助下處理請求,並將其呈現回用戶。只要業務想要對上述示例進行任何更改,一切都會很好。

考慮以下您必須根據業務需求更改應用程式的場景。

業務部門需要對“搜尋”模組進行一些更改。然後,您需要更改整個搜尋過程並重新部署您的應用程式。在這種情況下,您正在重新部署其他單元,而沒有任何更改。

Business Unit

現在,您的業務部門再次需要對“結賬”模組進行一些更改以包含“錢包”選項。您現在必須更改您的“結賬”模組並將其重新部署到伺服器中。請注意,您正在重新部署軟體包的不同模組,而我們對此沒有任何更改。這就是面向服務的架構,更具體地說,是微服務架構的概念。我們可以以這樣一種方式開發我們的單體應用程式,使軟體的每個模組都充當一個獨立的單元,能夠獨立處理單個業務任務。

請考慮以下示例。

在上述架構中,我們沒有建立任何具有緊湊端到端服務的 EAR 檔案。相反,我們透過將軟體的不同部分公開為服務來劃分它們。軟體的任何部分都可以透過使用各自的服務輕鬆地相互通訊。這就是微服務在現代 Web 應用程式中發揮重要作用的方式。

讓我們按照微服務的方式比較我們的購物車示例。我們可以將我們的購物車分解成不同的模組,例如“搜尋”、“篩選”、“結賬”、“購物車”、“推薦”等。如果我們想構建一個購物車門戶,那麼我們必須以這樣一種方式構建上述模組,使它們能夠相互連線,為您提供 24x7 的良好購物體驗。

優點和缺點

以下是使用微服務而不是使用單體應用程式的一些優點。

優點

  • 體積小 - 微服務是 SOA 設計模式的實現。建議您儘可能保持服務的小巧。基本上,服務不應該執行多個業務任務,因此它顯然比任何其他單體應用程式都更小且易於維護。

  • 專注 - 如前所述,每個微服務都設計用於執行一項業務任務。在設計微服務時,架構師應該關注服務的焦點,即其可交付成果。根據定義,一個微服務應該具有全棧特性,並且應該致力於交付唯一的業務屬性。

  • 自治 - 每個微服務都應該是整個應用程式的自治業務單元。因此,應用程式變得更加鬆散耦合,這有助於降低維護成本。

  • 技術異構性 - 微服務支援不同的技術在同一個業務單元中相互通訊,這有助於開發人員在正確的地方使用正確的技術。透過實現異構系統,人們可以獲得最大的安全性、速度和可擴充套件的系統。

  • 彈性 - 彈性是隔離軟體單元的屬性。微服務在構建方法中遵循高水平的彈性,因此當一個單元發生故障時,它不會影響整個業務。彈性是另一個實現高度可擴充套件和鬆散耦合系統的屬性。

  • 易於部署 - 由於整個應用程式被細分為小型單元,因此每個元件都應該具有全棧特性。與同類其他單體應用程式不同,所有這些都可以在任何環境中非常輕鬆地部署,並且時間複雜度更低。

以下是微服務架構的一些缺點。

缺點

  • 分散式系統 - 由於技術異構性,將使用不同的技術來開發微服務的不同部分。需要大量熟練的專業人員來支援這個大型異構分散式軟體。因此,分散式和異構性成為使用微服務的主要缺點之一。

  • 成本 - 微服務成本很高,因為您必須為不同的業務任務維護不同的伺服器空間。

  • 企業就緒性 - 微服務架構可以被認為是不同技術的集合,因為技術日新月異。因此,與傳統的軟體開發模型相比,使微服務應用程式具備企業就緒性非常困難。

微服務與 SOA

下表列出了 SOA 和微服務的某些特性,突出了在 SOA 上使用微服務的重要性。

元件 SOA 微服務
設計模式 SOA 是一種用於計算機軟體的設計範例,其中軟體元件以服務的形式公開給外部世界以供使用。 微服務是 SOA 的一部分。它是 SOA 的一種專門實現。
依賴性 業務單元相互依賴。 所有業務單元彼此獨立。
大小 軟體大小大於傳統軟體。 軟體體積小。
技術 技術棧少於微服務。 微服務本質上是異構的,因為使用精確的技術來執行特定任務。微服務可以被認為是許多技術的集合。
自治和專注 SOA 應用程式構建用於執行多個業務任務。 微服務應用程式構建用於執行單個業務任務。
性質 單體性質。 全棧性質。
部署 部署耗時。 部署非常容易。因此,它將耗時更少。
成本效益 更具成本效益。 成本效益較低。
可擴充套件性 與微服務相比較低。 完全擴充套件。
示例 讓我們考慮一個線上計程車預訂應用程式。如果我們想使用 SOA 構建該應用程式,那麼它的軟體單元將是 -
  • GetPayments 和 DriverInformation 和 MappingDataAPI
  • AuthenticateUsersAnd DriversAPI
如果使用微服務架構構建相同的應用程式,那麼它的 API 將是 -
  • SubmitPaymentsService
  • GetDriverInfoService
  • GetMappingDataService
  • AuthenticateUserService
  • AuthenticateDriverService

微服務架構 - 擴充套件

擴充套件是將軟體分解成不同單元的過程。擴充套件也以可擴充套件性的形式定義。可擴充套件性是實施應用程式更高階功能的潛力。它有助於提高應用程式的安全、永續性和可維護性。行業中遵循三種類型的擴充套件程式。以下是不同的擴充套件方法以及相應的現實生活示例。

X 軸擴充套件

X軸縮放也稱為水平縮放。在此過程中,整個應用程式被細分為不同的水平部分。通常,任何 Web 伺服器應用程式都可以具有這種型別的縮放。考慮一個遵循水平縮放的普通 MVC 架構,如下圖所示。

X-Axis Scaling

例如,我們可以考慮任何 JSP servlet 應用程式。在此應用程式中,控制器控制每個請求,並在必要時透過與模型通訊來生成檢視。通常,單體應用程式遵循此縮放方法。X軸縮放本質上非常基礎,並且耗時很少。在這種方法中,一個軟體將根據其負責的不同任務進行縮放。例如,控制器負責控制傳入和傳出的請求,檢視負責向瀏覽器中的使用者展示業務功能,而模型負責儲存我們的資料,並充當資料庫。

Y軸縮放

Y軸縮放也稱為垂直縮放,它包括任何資源級別的縮放。任何 DBaaS 或 Hadoop 系統都可以被認為是 Y軸縮放的。在這種型別的縮放中,使用者的請求透過實現某些邏輯來重定向和限制。

讓我們以 Facebook 為例。Facebook 需要每秒處理 179 萬用戶;因此,控制流量是 Facebook 網路工程師的一項重大責任。為了克服任何危險,他們遵循 Y軸縮放,其中包括同時執行多個具有相同應用程式的伺服器。現在,為了控制這種巨大流量級別,Facebook 將來自一個區域的所有流量重定向到特定伺服器,如影像所示。從架構語言的角度來看,這種基於區域的流量傳輸稱為負載均衡。

Y-Axis Scaling

這種將資源分解成小的獨立業務單元的方法稱為 Y軸縮放。

Z軸縮放

X軸和 Y軸縮放很容易理解。但是,一個應用程式也可以在業務級別進行縮放,這稱為 Z軸縮放。以下是按業務單元的不同垂直方向擴展出租車服務應用程式的示例。

Driver Management

縮放的優勢

  • 成本 - 正確的軟體縮放將降低維護成本。

  • 效能 - 由於松耦合,正確縮放的軟體的效能始終優於未縮放的軟體。

  • 負載分配 - 使用不同的技術,我們可以輕鬆地維護伺服器負載。

  • 重用 - 軟體的可擴充套件性也提高了軟體的可用性。

微服務架構 - 藍圖

微服務在內部實現了 SOA。從更廣泛的意義上說,我們可以將其視為一個 SOA 應用程式的子集。

規則和工作流

以下是開發微服務時需要注意的原則。

  • 高內聚性 - 所有業務模型都需要儘可能細化到最小的業務部分。每個服務都應該專注於執行一項業務任務。

  • 獨立性 - 所有服務都應該具有完整的功能,並且彼此獨立。

  • 以業務域為中心 - 軟體將根據業務單元進行模組化,而不是基於層級。

  • 自動化 - 測試部署將自動化。儘量減少人工干預。

  • 可觀察性 - 每個服務都將具有完整的功能,並且應該像企業應用程式一樣獨立部署和可觀察。

團隊管理

“兩個披薩規則”是一種限制微服務開發團隊參與者數量的規則。根據此規則,一個應用程式的團隊成員數量應該很小,以便兩個披薩可以餵飽他們。通常,人數不應超過 8 人。由於微服務具有完整的功能,因此團隊也具有完整的功能。為了提高生產力,我們需要建立一個最多 8 名成員的團隊,其中包含該服務所需的所有專業知識。

任務管理

任務在軟體開發生命週期中扮演著重要的角色。開發大型應用程式可以分解成幾個小的任務單元。假設我們需要開發一個像 Facebook 這樣的應用程式。那麼,“登入”功能可以被視為整個構建過程中的一個任務。每個任務的進度都需要在高技能專業人員的監督下得到妥善監控。敏捷是行業中遵循的著名流程結構,以保持良好的任務管理。

不同元素

到目前為止,我們已經瞭解了什麼是微服務以及在現代 MVC 架構之上它有哪些基本需求。在本章中,我們將學習該架構的不同元素,這些元素對於服務同樣重要。

服務的類別

從微服務這個名稱來看,我們假設它將是一個可以透過 HTTP 協議使用的服務,但是我們需要知道使用這種架構可以構建哪些型別的服務。以下是可以使用微服務架構實現的服務列表。

平臺即服務 [PaaS] - 在這種面向服務的架構中,平臺作為一種工具提供,可以根據業務需求進行定製。PaaS 在移動應用程式開發中發揮著重要作用。PaaS 最好的例子是 Google App Engine,其中 Google 提供了不同的實用平臺來構建您的應用程式。PaaS 最初是為了為開發人員提供內建的架構或基礎設施而開發的。它以大大減少的時間顯著降低了高階程式設計的複雜性。以下是 Google 提供的 PaaS 的快照。

Google Cloud Platform

軟體即服務 [SaaS] - 軟體即服務是一種軟體許可業務,其中軟體集中託管並以訂閱方式獲得許可。SaaS 主要可以透過瀏覽器訪問,並且在許多業務垂直領域(如人力資源管理 (HRM)、企業資源規劃 (ERP)、客戶關係管理 (CRM) 等)中是一種非常常見的架構模式。以下螢幕截圖顯示了 Oracle 提供的不同 SaaS 的示例。

Common Infrastructure Services

基礎設施即服務 [IaaS] - 基礎設施在 IT 行業中發揮著重要作用。使用雲計算,一些組織將其虛擬基礎設施作為服務提供。IaaS 有助於在軟體開發中帶來敏捷性、成本效益、安全性、效能、生產力等。Amazon EC2 和 Microsoft Azure 是 IaaS 的最大示例。下圖描繪了 AWS 的一個示例,其中資料中心作為 IaaS 提供。

Data Center Services

資料即服務 [DaaS] - 資訊科技處理資料,一些行業領導者認為資料將成為社會新的支柱。DaaS 是一種服務型別,其中資料與企業集團共享以進行研究和分析。DaaS 為資料訪問層帶來了簡單性、敏捷性和安全性。以下是一個 Oracle Data Cloud 的示例,您可以訪問或許可它以滿足您自己的業務需求。

Oracle Data cloud

後端即服務 [BaaS] - BaaS 也稱為 MBaaS,即移動後端即服務。在這種型別的服務中,應用程式的後端將提供給業務部門以供其自身的業務冒險。所有推送通知、社交網路服務都屬於此類服務。Facebook 和 Twitter 是知名的 BaaS 服務提供商的例子。

安全

在處理大量客戶資料時,安全性起著重要作用。安全問題與市場上所有型別的服務相關聯。無論您使用哪種雲 - 私有、公共、混合等,都應在所有級別維護安全性。整個安全問題可以大致細分為以下幾個部分 -

  • 服務提供商面臨的安全問題 - 這種型別的安全問題是服務提供商(如 Google、Amazon 等)面臨的。為了確保安全保護,有必要對客戶端進行背景調查,尤其是那些可以直接訪問雲核心部分的客戶端。

  • 消費者面臨的安全問題 - 雲具有成本效益,因此在各行各業中得到廣泛使用。一些組織將使用者詳細資訊儲存在第三方資料中心,並在需要時提取資料。因此,必須維護安全級別,以確保一個客戶的任何私人資料對任何其他使用者不可見。

為了防止上述安全問題,以下是組織使用的一些防禦機制。

  • 威懾控制 - 瞭解您的潛在威脅以減少網路攻擊。

  • 預防控制 - 維護高階身份驗證策略以訪問您的雲。

  • 偵查控制 - 監控您的使用者並檢測任何潛在風險。

  • 糾正控制 - 與不同的團隊密切合作,修復在偵查控制階段出現的任何問題。

組合模式

軟體構成是指構建軟體產品的方式。基本上,它涉及高階軟體架構圖,其中軟體的不同模組將為了特定的業務目標而進行通訊。在本章中,我們將學習組織中廣泛使用的不同軟體組合模式。在微服務中,我們將每個功能拆分為一個程序。這些服務中的每一個都將是獨立的,並且具有完整的功能。

功能分解在構建微服務中發揮著重要作用。它為您的應用程式提供了敏捷性、靈活性和可擴充套件性。

聚合器模式

聚合器模式是在開發微服務時可以實現的最簡單的 Web 模式。在此組合模式中,一個簡單的 Web 模組將充當負載均衡器,這意味著它將根據需要呼叫不同的服務。下圖顯示了一個帶有聚合器設計的簡單微服務 Web 應用程式。如以下影像所示,“聚合器”負責依次呼叫不同的服務。如果我們需要對服務 A、B 和 C 的結果應用任何業務邏輯,那麼我們可以在聚合器本身中實現業務邏輯。

Aggregator Pattern

聚合器可以再次作為另一個服務公開給外部世界,並在需要時被其他人使用。在開發聚合器模式 Web 服務時,我們需要記住我們的每個服務 A、B 和 C 都應該有自己的快取層,並且應該具有完整的功能。

代理模式

代理微服務模式是聚合器模型的一個變體。在此模型中,我們將使用代理模組而不是聚合模組。代理服務可以單獨呼叫不同的服務。

Proxy Pattern

在代理模式中,我們可以透過提供一個虛擬代理層來構建一層額外的安全性。此層的作用類似於介面。

鏈式模式

顧名思義,這種組合模式將遵循鏈式結構。在這裡,我們不會在客戶端和服務層之間使用任何東西。相反,我們將允許客戶端直接與服務通訊,並且所有服務都將以這樣一種方式連結起來,即一個服務的輸出將成為下一個服務的輸入。下圖顯示了一個典型的鏈式模式微服務。

Chained Pattern

此架構的一個主要缺點是,客戶端將被阻塞,直到整個過程完成。因此,強烈建議將鏈的長度保持儘可能短。

分支微服務模式

分支微服務是聚合器模式和鏈式模式的擴充套件版本。在這種設計模式中,客戶端可以直接與服務通訊。此外,一個服務可以同時與多個服務通訊。以下是分支微服務的示意圖。

Branch Microservice Pattern

分支微服務模式允許開發人員動態配置服務呼叫。所有服務呼叫都將併發進行,這意味著服務 A 可以同時呼叫服務 B 和 C。

共享資源模式

共享資源模式實際上是前面提到的所有型別模式的集合。在這種模式下,客戶端或負載均衡器將在必要時直接與每個服務通訊。這是大多陣列織廣泛採用的最有效的設計模式。以下是共享資源設計模式的示意圖。

Shared Resource Pattern

微服務架構 - SOA 實戰

在本章中,我們將開發一個基於 CRUD 的 SOA 架構應用程式。在後續章節中,我們將把此服務分解成微服務,並學習 SOA 和微服務架構之間的基本區別。

系統配置和設定

在本節中,我們將構建一個示例 CRUD 應用程式,每當我們呼叫我們的服務時,它將返回一個 JSON 物件作為響應。我們將使用 Jersey 框架來開發它。以下是設定本地系統環境的步驟。

開發 CRUD 應用程式

步驟 1 - 我們將使用 NetBeans 作為開發 IDE。請從 NetBeans 官方網站下載並安裝最新版本 https://netbeans.org/downloads/

步驟 2 - 開啟 NetBeans IDE。轉到“檔案 -> 新建專案”。將彈出以下螢幕截圖。選擇“Maven”作為類別,選擇“從 ArchType 建立專案”作為專案,然後點選下一步。

Screenshot Pops Up

這將下載建立第一個 Maven 專案和 RESTful Web 服務所需的所有 jar 檔案。

步驟 3 - 在上一步點選下一步按鈕後,將出現以下螢幕截圖。在這裡,您必須指定 Maven 原型。

Maven Archetype

在搜尋框中,搜尋“Jersey-archType-Webapp(2.16)”並選中“顯示舊版本”複選框。

步驟 4 - 選擇後,您將被重定向到以下螢幕。從列表中選擇首選的 jar 並點選下一步繼續。

Redirected Screen

步驟 5 - 在此步驟中,您需要提供專案的名稱及其 Group Id 以及包詳細資訊。提供所有這些資訊後,點選完成繼續。

Group Id

步驟 6 - 您已完成工作區設定。專案目錄將如下所示。

Workspace Setup

檢視您的“依賴項”資料夾,您會發現 Maven 已自動下載了此專案所需的所有 jar 檔案。

Dependencies

步驟 7 - 您的工作區已設定好,您可以開始編碼了。繼續並建立四個類和包,如下面的螢幕截圖所示。您可以看到 MyResource.java 已經由 Maven 建立,因為 Maven 足夠智慧,可以檢測到您將要構建自己的 Web 服務。

Source Packages

步驟 8 - 完成上述步驟後,我們將構造我們的 POJO 類 UserProfile.java,如下所示。

package com.tutorialspoint.userprofile.Model;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class UserProfile {
   private long ProId;
   private String FName;
   private String LName;
   private String Add;
   public UserProfile(){}
   
   public UserProfile(long Proid, String Fname, String Lname,String Add) {
      this.ProId = Proid;
      this.FName = Fname;
      this.LName = Lname;
      this.Add = Add;
   }
   public long getProId() {
      return ProId;
   }
   public void setProId(long ProId) {
      this.ProId = ProId;
   }
   public String getFName() {
      return FName;
   }
   public void setFName(String FName) {
      this.FName = FName;
   }
   public String getLName() {
      return LName;
   }
   public void setLName(String LName) {
      this.LName = LName;
   }
   public String getAdd() {
      return Add;
   }
   public void setAdd(String Add) {
      this.Add = Add;
   }
}

步驟 9 - 現在我們將建立我們的資料庫類。由於這是學習資料的一部分,我們不會使用任何資料庫作為我們的資料庫。我們將使用內建的 Java 記憶體作為我們的臨時記憶體。正如您在以下程式碼集中看到的,我們將使用 MAP 作為我們的資料庫。我們執行的所有 Web 服務操作都將在此類中定義的 MAP 上進行。

package com.tutorialspoint.userprofile.DAO;

import com.tutorialspoint.userprofile.Model.UserProfile;

import java.util.HashMap;
import java.util.Map;

public class DatabaseClass {
   private static Map<Long,UserProfile> messages = new HashMap<Long,UserProfile>();
   public static Map<Long,UserProfile> getUsers() {
      return messages; 
      // Each time this method will return entire map as an instance of database
   }
}

步驟 10 - 現在讓我們構建我們的服務類。繼續並將以下程式碼集複製貼上到“ProfileService.java”類中。這是我們將宣告所有要公開給外部世界的 Web 服務方法的類。我們需要建立一個數據庫類的引用,以便我們的臨時資料庫可以在此類中訪問。

package com.tutorialspoint.userprofile.service;

import com.tutorialspoint.userprofile.DAO.DatabaseClass;
import com.tutorialspoint.userprofile.Model.UserProfile;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class ProfileService {
   private Map<Long,UserProfile> Userprofiles = DatabaseClass.getUsers();
   
   // Creating some predefine profile and populating the same in the map
   public ProfileService() {
      UserProfile m1 = new UserProfile(1L,"Tutorials1","Point1","TutorialsPoint.com");
      UserProfile m2 = new UserProfile(2L,"Tutorials2","Point2","TutorialsPoint.com2");
      UserProfile m3 = new UserProfile(3L,"Tutorials3","Point3","TutorialsPoint.com3");
      UserProfile m4 = new UserProfile(4L,"Tutorials4","Point4","TutorialsPoint.com4");
      
      Userprofiles.put(1L, m1);
      Userprofiles.put(2L, m2);
      Userprofiles.put(1L, m3);
      Userprofiles.put(2L, m4);
   }
   
   //Method to fetch all profile
   public List<UserProfile> getAllProfile() {
      List<UserProfile> list = new ArrayList<UserProfile>(Userprofiles.values());
      return list;
   }  // Method to fetch only one profile depending on the ID provided
   
   public UserProfile getProfile(long id) {
      return Userprofiles.get(id);
   }  //Method to add profile
   
   public UserProfile addProfile(UserProfile UserProfile) {
      UserProfile.setProId(Userprofiles.size()+1);
      Userprofiles.put(UserProfile.getProId(), UserProfile);
      return UserProfile;
   }  //method to update Profile

   public UserProfile UpdateProfile(UserProfile UserProfile) {
      if(UserProfile.getProId()<=0) { 
         return null;
      } else { 
         Userprofiles.put(UserProfile.getProId(), UserProfile);
         return UserProfile;
      }
   } //method to delete profile
   
   public void RemoveProfile(long Id) {
      Userprofiles.remove(Id);
   }
}

步驟 11 - 在此步驟中,我們將建立我們的資源類,該類將與 URL 連結,並將呼叫相應的服務。

package com.tutorialspoint.userprofile.Resource;

import com.tutorialspoint.userprofile.Model.UserProfile;
import com.tutorialspoint.userprofile.service.ProfileService;

import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/Profile")
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)

public class ProfileResource {
   ProfileService messageService = new ProfileService();
   
   @GET
   public List<UserProfile> getProfile() {
      return messageService.getAllProfile();
   }

   @GET
   @Path("/{ProID}")
   public UserProfile getProfile(@PathParam("ProID")long Id) {
      return messageService.getProfile(Id);
   }

   @POST
   public UserProfile addProfile(UserProfile profile) {
      return messageService.addProfile(profile);
   }

   @PUT
   @Path("/{proID}")
   public UserProfile UpdateProfile(@PathParam("proID")long Id,UserProfile UserProfile) {
      UserProfile.setProId(Id);
      return messageService.UpdateProfile(UserProfile);
   }
   
   @DELETE
   @Path("/{ProID}")
   public void deleteProfile(@PathParam("ProID")long Id) {
      messageService.RemoveProfile(Id);
   }
}

步驟 12 - 清理構建專案並執行它。如果一切順利,您應該在瀏覽器中獲得以下輸出,同時訪問https://:8080/UserProfile/webapi/Profile” URL。

您可以看到使用 XML 表示法填充了不同的條目。

User Profiles

可以透過使用正確的 Method URL 透過 Postman 測試不同的方法。

@GET 方法 - 以下螢幕截圖演示瞭如何獲取 get 請求的所需結果,該結果返回所有使用者詳細資訊。

Screenshot Demonstrates

@POST - 以下請求可用於測試我們的 Post 方法。請注意 proId 如何自動生成。

Post method

@PUT - 此方法將更新條目。以下螢幕截圖演示了 Jersey 如何從請求 URL 中獲取 proId 並更新相同的使用者配置檔案回覆。

Same User Profile Reply

同樣,您可以檢查 Web 服務中可用的其他方法。

在上一節中,我們開發了一個服務,該服務將公開 CRUD 功能。現在,每當我們嘗試在我們的應用程式中實現此服務時,我們需要建立此應用程式的客戶端並將其附加到我們的應用程式。在本章中,我們將學習如何使用微服務的概念構建此功能。以下是使用上述步驟構建的應用程式的示意圖。

Actor

參與者應該是我們服務的入口點。在這種情況下,“ProfileResource.java”承擔參與者的職責。此類將呼叫不同的方法來執行不同的操作,例如新增、更新和刪除。

CRUD 應用程式的分解

根據微服務的主要原則,我們需要為每個模組只有一個業務任務,因此一個參與者不應該負責所有四個 CRUD 功能。考慮以下示例,我們引入了一些新角色,這樣您就可以清楚地瞭解微服務是 SOA 的架構表示。

Architectural Representation

“主要使用者”是與“應用程式控制器”通訊以滿足其需求的使用者。“應用程式控制器”只是根據終端使用者的請求呼叫不同的“資源管理器”。“資源管理器”執行需要完成的工作。讓我們快速瞭解應用程式不同單元的不同角色。

  • 終端使用者/主要使用者 - 請求某些資源到應用程式控制器。

  • 應用程式 - 接收請求並將請求轉發到特定的資源管理器。

  • 資源管理器 - 執行更新、刪除和新增使用者的實際工作。

請檢視一個類的總職責是如何分佈在不同的其他類中的。

微服務架構 - MSA 實戰

在本章中,我們將構建一個微服務應用程式,該應用程式將使用不同的可用服務。我們都知道,微服務不是構建應用程式的經濟有效的方式,因為我們構建的每個服務本質上都是全棧的。在本地環境中構建微服務需要高階的系統配置,因為您需要擁有四個伺服器例項以保持執行,以便可以在某個時間點使用它。為了構建我們的第一個微服務,我們將使用一些可用的 SOA 端點,並在我們的應用程式中使用它們。

系統配置和設定

在進一步進入構建階段之前,請相應地準備您的系統。您將需要一些公共 Web 服務。您可以輕鬆地透過 Google 搜尋。如果您想使用 SOAP Web 服務,那麼您將獲得一個 WSDL 檔案,並且您需要從中使用特定的 Web 服務。對於 REST 服務,您只需要一個連結來使用它。在本例中,您將在一個應用程式中使用三個不同的 Web 服務“SOAP”、“REST”和“自定義”。

應用程式架構

您將使用微服務實施計劃建立一個 Java 應用程式。您將建立一個自定義服務,此服務的輸出將作為其他服務的輸入。

以下是開發微服務應用程式需要遵循的步驟。

步驟 1:建立 SOAP 服務的客戶端 - 有許多免費的 Web API 可用於學習 Web 服務。出於本教程的目的,使用“http://www.webservicex.net/”的 GeoIP 服務。WSDL 檔案在其網站上的以下連結中提供“webservicex.net. 要從此 WSDL 檔案生成客戶端,您需要做的就是在終端中執行以下命令。

wsimport http://www.webservicex.net/geoipservice.asmx?WSDL

此命令將在一個名為“SEI”的資料夾下生成所有必需的客戶端檔案,該資料夾以服務端點介面命名。

步驟 2:建立您的自定義 Web 服務 - 遵循本教程前面階段中提到的相同過程,並構建一個名為“CustomRest”的基於 Maven 的 REST api。完成後,您將找到一個名為“MyResource.java”的類。繼續並使用以下程式碼更新此類。

package com.tutorialspoint.customrest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("myresource")
public class MyResource {
   @GET
   @Produces(MediaType.TEXT_PLAIN)
   
   public String getIt() {
      return "IND|INDIA|27.7.65.215";
   }
}

一切完成後,繼續並在伺服器上執行此應用程式。您應該在瀏覽器中獲得以下輸出。

Web Service

這是 Web 伺服器,它在被呼叫時返回一個字串物件。這是提供可由其他應用程式使用以生成記錄的輸入的服務。

步驟 3:配置另一個 Rest API - 在此步驟中,使用位於services.groupkt.com. 的另一個 Web 服務。呼叫時,這將返回一個 JSON 物件。

步驟 4:建立 JAVA 應用程式 - 透過選擇“新建專案”->“JAVA 專案”並點選完成建立一個普通的 Java 應用程式,如下面的螢幕截圖所示。

JAVA Application

步驟 5:新增 SOAP 客戶端 - 在步驟 1 中,您已為 SOAP Web 服務建立了客戶端檔案。繼續並將這些客戶端檔案新增到您當前的專案中。成功新增客戶端檔案後,您的應用程式目錄將如下所示。

SOAP web service

步驟 6:建立您的主應用程式 - 建立您的主類,您將在其中使用所有這三個 Web 服務。右鍵單擊源專案並建立一個名為“MicroServiceInAction.java”的新類。接下來的任務是從這裡呼叫不同的 Web 服務。

步驟 7:呼叫您的自定義 Web 服務 - 為此,請繼續並將以下程式碼集新增到實現呼叫您自己的服務。

try {
   url = new URL("https://:8080/CustomRest/webapi/myresource");
   conn = (HttpURLConnection) url.openConnection();
   conn.setRequestMethod("GET");
   conn.setRequestProperty("Accept", "application/json");
   
   if (conn.getResponseCode() != 200) {
      throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
   }
   
   BufferedReader br = new BufferedReader(new InputStreamReader(
      (conn.getInputStream())));
   while ((output = br.readLine()) != null) {
      inputToOtherService = output;
   }
   conn.disconnect();

} catch (MalformedURLException e) {
   e.printStackTrace();
} catch (IOException e) {
   e.printStackTrace();
}

步驟 8:使用 SOAP 服務 - 您已生成客戶端檔案,但您不知道在整個包中應該呼叫哪個方法?為此,您需要再次參考用於生成客戶端檔案的 WSDL。每個 WSDL 檔案都應該有一個“wsdl:service”標籤,搜尋此標籤。它應該是該 Web 服務的入口點。以下是此應用程式的服務端點。

WSDL Service

現在您需要在您的應用程式中實現此服務。以下是您需要實現 SOAP Web 服務的 Java 程式碼集。

GeoIPService newGeoIPService = new GeoIPService();
GeoIPServiceSoap newGeoIPServiceSoap = newGeoIPService.getGeoIPServiceSoap();
GeoIP newGeoIP = newGeoIPServiceSoap.getGeoIP(Ipaddress);  
// Ipaddress is output of our own web service.

System.out.println("Country Name from SOAP Webserivce ---"+newGeoIP.getCountryName());

步驟 9:使用 REST Web 服務 - 到目前為止,已經使用了兩個服務。在此步驟中,將藉助您的自定義 Web 服務使用具有自定義 URL 的另一個 REST Web 服務。使用以下程式碼集來執行此操作。

String url1="http://services.groupkt.com/country/get/iso3code/";//customizing the Url
url1 = url1.concat(countryCode);

try {
   URL url = new URL(url1);
   HttpURLConnection conn = (HttpURLConnection) url.openConnection();
   conn.setRequestMethod("GET");
   conn.setRequestProperty("Accept", "application/json");
   
   if (conn.getResponseCode() != 200) {
      throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
   }
   
   BufferedReader br = new BufferedReader(new InputStreamReader(
      (conn.getInputStream())));
   while ((output = br.readLine()) != null) {
      System.out.println(output);
   }
   conn.disconnect();

} catch (MalformedURLException e) {
   e.printStackTrace();
} catch (IOException e) {
   e.printStackTrace();
}

步驟 10:使用所有服務 - 假設您的“CustomRest” Web 服務正在執行並且您已連線到網際網路,如果一切成功完成,則以下應該是您的合併主類。

package microserviceinaction;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.StringTokenizer;

import net.webservicex.GeoIP;
import net.webservicex.GeoIPService;
import net.webservicex.GeoIPServiceSoap;

public class MicroServiceInAction {
   static URL url;
   static HttpURLConnection conn;
   static String output;
   static String inputToOtherService;
   static String countryCode;
   static String ipAddress;
   static String CountryName;
   public static void main(String[] args) {
      //consuming of your own web service
      try {
         url = new URL("https://:8080/CustomRest/webapi/myresource");
         conn = (HttpURLConnection) url.openConnection();
         conn.setRequestMethod("GET");
         conn.setRequestProperty("Accept", "application/json");
         
         if (conn.getResponseCode() != 200) {
            throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
         }
         
         BufferedReader br = new BufferedReader(new InputStreamReader(
            (conn.getInputStream())));
         while ((output = br.readLine()) != null) {
            inputToOtherService = output;
         }
         conn.disconnect();
      
      } catch (MalformedURLException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
      
      //Fetching IP address from the String and other information
      StringTokenizer st = new StringTokenizer(inputToOtherService);
      countryCode = st.nextToken("|");
      CountryName = st.nextToken("|");
      ipAddress = st.nextToken("|");
      
      // Call to SOAP web service with output of your web service--- 
      // getting the location of our given IP address
      String Ipaddress = ipAddress;
      GeoIPService newGeoIPService = new GeoIPService();
      GeoIPServiceSoap newGeoIPServiceSoap = newGeoIPService.getGeoIPServiceSoap();
      GeoIP newGeoIP = newGeoIPServiceSoap.getGeoIP(Ipaddress);
      System.out.println("Country Name from SOAP Webservice ---"+newGeoIP.getCountryName());
      
      // Call to REST API --to get all the details of our country
      String url1 = "http://services.groupkt.com/country/get/iso3code/"; //customizing the Url
      url1 = url1.concat(countryCode);
      
      try {
         URL url = new URL(url1);
         HttpURLConnection conn = (HttpURLConnection) url.openConnection();
         conn.setRequestMethod("GET");
         conn.setRequestProperty("Accept", "application/json");
			
         if (conn.getResponseCode() != 200) {
            throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode());
         }
      
         BufferedReader br = new BufferedReader(new InputStreamReader(
            (conn.getInputStream())));
         while ((output = br.readLine()) != null) {
            System.out.println(output);
         }
      
         conn.disconnect();
      } catch (MalformedURLException e) {
         e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

執行此檔案後,您將在控制檯中看到以下輸出。您已成功開發了您的第一個微服務應用程式。

Output in The Console
廣告