14 微服務電商【黑馬樂優商城】:day02-springcloud(理論篇一:HttpClient的簡單使用)

本項目的筆記和資料的Download,請點擊這一句話自行獲取。html

day01-springboot(理論篇) ;day01-springboot(實踐篇)前端

day02-springcloud(理論篇一:HttpClient的簡單使用)  ;java

14 微服務電商【黑馬樂優商城】:day02-springcloud


0.學習目標

  • 瞭解系統架構的演變
  • 瞭解RPC與Http的區別
  • 掌握HttpClient的簡單使用
  • 知道什麼是SpringCloud
  • 獨立搭建Eureka註冊中心
  • 獨立配置Robbin負載均衡

1.系統架構演變

隨着互聯網的發展,網站應用的規模不斷擴大。需求的激增,帶來的是技術上的壓力。系統架構也所以也不斷的演進、升級、迭代。程序員

從單一應用,到垂直拆分,到分佈式服務,到SOA面向服務,以及如今火熱的微服務架構,還有在Google帶領下來勢洶涌的Service Mesh。web

1.1. 集中式架構

當網站流量很小時,只需一個應用,將全部功能都部署在一塊兒,以減小部署節點和成本。此時,用於簡化增刪改查工做量的數據訪問框架(ORM)是影響項目開發的關鍵。spring

存在的問題:數據庫

  • 代碼耦合,開發維護困難
  • 沒法針對不一樣模塊進行鍼對性優化
  • 沒法水平擴展
  • 單點容錯率低,併發能力差

1.2.垂直拆分

當訪問量逐漸增大,單一應用沒法知足需求,此時爲了應對更高的併發和業務需求,咱們根據業務功能對系統進行拆分:apache

優勢:編程

  • 系統拆分實現了流量分擔,解決了併發問題
  • 能夠針對不一樣模塊進行優化
  • 方便水平擴展,負載均衡,容錯率提升

缺點:json

  • 系統間相互獨立,會有不少重複開發工做,影響開發效率

1.3.分佈式服務

當垂直應用愈來愈多,應用之間交互不可避免,將核心業務抽取出來,做爲獨立的服務,逐漸造成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。此時,用於提升業務複用及整合的分佈式調用是關鍵。

 

優勢:

  • 將基礎服務進行了抽取,系統間相互調用,提升了代碼複用和開發效率

缺點:

  • 系統間耦合度變高,調用關係錯綜複雜,難以維護

1.4.服務治理(SOA)

當服務愈來愈多,容量的評估,小服務資源的浪費等問題逐漸顯現,此時需增長一個調度中心基於訪問壓力實時管理集羣容量,提升集羣利用率。此時,用於提升機器利用率的資源調度和治理中心(SOA)是關鍵

之前出現了什麼問題?

  • 服務愈來愈多,須要管理每一個服務的地址
  • 調用關係錯綜複雜,難以理清依賴關係
  • 服務過多,服務狀態難以管理,沒法根據服務狀況動態管理

服務治理要作什麼?

  • 服務註冊中心,實現服務自動註冊和發現,無需人爲記錄服務地址
  • 服務自動訂閱,服務列表自動推送,服務調用透明化,無需關心依賴關係
  • 動態監控服務狀態監控報告,人爲控制服務狀態

缺點:

  • 服務間會有依賴關係,一旦某個環節出錯會影響較大
  • 服務關係複雜,運維、測試部署困難,不符合DevOps思想 

1.5.微服務

前面說的SOA,英文翻譯過來是面向服務。微服務,彷佛也是服務,都是對系統進行拆分。所以二者很是容易混淆,但其實缺有一些差異:

微服務的特色:

  • 單一職責:微服務中每個服務都對應惟一的業務能力,作到單一職責
  • 微:微服務的服務拆分粒度很小,例如一個用戶管理就能夠做爲一個服務。每一個服務雖小,但「五臟俱全」。
  • 面向服務:面向服務是說每一個服務都要對外暴露服務接口API。並不關心服務的技術實現,作到與平臺和語言無關,也不限定用什麼技術實現,只要提供Rest的接口便可。
  • 自治:自治是說服務間互相獨立,互不干擾
    • 團隊獨立:每一個服務都是一個獨立的開發團隊,人數不能過多。
    • 技術獨立:由於是面向服務,提供Rest接口,使用什麼技術沒有別人干涉
    • 先後端分離:採用先後端分離開發,提供統一Rest接口,後端不用再爲PC、移動段開發不一樣接口
    • 數據庫分離:每一個服務都使用本身的數據源
    • 部署獨立,服務間雖然有調用,但要作到服務重啓不影響其它服務。有利於持續集成和持續交付。每一個服務都是獨立的組件,可複用,可替換,下降耦合,易維護

微服務結構圖:

 


2.遠程調用方式

不管是微服務仍是SOA,都面臨着服務間的遠程調用。那麼服務間的遠程調用方式有哪些呢?

常見的遠程調用方式有如下兩種:

  • RPC:Remote Produce Call遠程過程調用,相似的還有RMI。自定義數據格式,基於原生TCP通訊,速度快,效率高。如今熱門的dubbo,就是RPC的典型

  • Http:http實際上是一種網絡傳輸協議,基於TCP,規定了數據傳輸的格式。如今客戶端瀏覽器與服務端通訊基本都是採用Http協議。也能夠用來進行遠程服務調用。缺點是消息封裝臃腫。

    如今熱門的Rest風格,就能夠經過http協議來實現

2.1.認識RPC

RPC,即 Remote Procedure Call(遠程過程調用),是一個計算機通訊協議。 該協議容許運行於一臺計算機的程序調用另外一臺計算機的子程序,而程序員無需額外地爲這個交互做用編程。說得通俗一點就是:A計算機提供一個服務,B計算機能夠像調用本地服務那樣調用A計算機的服務。

經過上面的概念,咱們能夠知道,實現RPC主要是作到兩點:

  • 實現遠程調用其餘計算機的服務
    • 要實現遠程調用,確定是經過網絡傳輸數據。A程序提供服務,B程序經過網絡將請求參數傳遞給A,A本地執行後獲得結果,再將結果返回給B程序。這裏須要關注的有兩點:
      • 1)採用何種網絡通信協議?
        • 如今比較流行的RPC框架,都會採用TCP做爲底層傳輸協議
      • 2)數據傳輸的格式怎樣?
        • 兩個程序進行通信,必須約定好數據傳輸格式。就比如兩我的聊天,要用同一種語言,不然沒法溝通。因此,咱們必須定義好請求和響應的格式。另外,數據在網路中傳輸須要進行序列化,因此還須要約定統一的序列化的方式。
  • 像調用本地服務同樣調用遠程服務
    • 若是僅僅是遠程調用,還不算是RPC,由於RPC強調的是過程調用,調用的過程對用戶而言是應該是透明的,用戶不該該關心調用的細節,能夠像調用本地服務同樣調用遠程服務。因此RPC必定要對調用的過程進行封裝

RPC調用流程圖:

2.2.認識Http

Http協議:超文本傳輸協議,是一種應用層協議。規定了網絡傳輸的請求格式、響應格式、資源定位和操做的方式等。可是底層採用什麼網絡傳輸協議,並無規定,不過如今都是採用TCP協議做爲底層傳輸協議。說到這裏,你們可能以爲,Http與RPC的遠程調用很是像,都是按照某種規定好的數據格式進行網絡通訊,有請求,有響應。沒錯,在這點來看,二者很是類似,可是仍是有一些細微差異。

  • RPC並無規定數據傳輸格式,這個格式能夠任意指定,不一樣的RPC協議,數據格式不必定相同。
  • Http中還定義了資源定位的路徑,RPC中並不須要
  • 最重要的一點:RPC須要知足像調用本地服務同樣調用遠程服務,也就是對調用過程在API層面進行封裝。Http協議沒有這樣的要求,所以請求、響應等細節須要咱們本身去實現。
    • 優勢:RPC方式更加透明,對用戶更方便。Http方式更靈活,沒有規定API和語言,跨語言、跨平臺
    • 缺點:RPC方式須要在API層面進行封裝,限制了開發的語言環境。

例如咱們經過瀏覽器訪問網站,就是經過Http協議。只不過瀏覽器把請求封裝,發起請求以及接收響應,解析響應的事情都幫咱們作了。若是是不經過瀏覽器,那麼這些事情都須要本身去完成。

2.3.如何選擇?

既然兩種方式均可以實現遠程調用,咱們該如何選擇呢?

  • 速度來看,RPC要比http更快,雖然底層都是TCP,可是http協議的信息每每比較臃腫,不過能夠採用gzip壓縮。
  • 難度來看,RPC實現較爲複雜,http相對比較簡單
  • 靈活性來看,http更勝一籌,由於它不關心實現細節,跨平臺、跨語言。

所以,二者都有不一樣的使用場景:

  • 若是對效率要求更高,而且開發過程使用統一的技術棧,那麼用RPC仍是不錯的。
  • 若是須要更加靈活,跨語言、跨平臺,顯然http更合適

那麼咱們該怎麼選擇呢?

微服務,更增強調的是獨立、自治、靈活。而RPC方式的限制較多,所以微服務框架中,通常都會採用基於Http的Rest風格服務。


3.Http客戶端工具

既然微服務選擇了Http,那麼咱們就須要本身來實現對請求和響應的處理。好在開源世界已經有不少的http客戶端工具,可以幫助咱們作這些事情,例如:

  • HttpClient
  • OKHttp
  • URLConnection

接下來,咱們就一塊兒瞭解一款比較流行的客戶端工具:HttpClient

3.1.HttpClient

3.1.1.介紹

HttpClient是Apache公司的產品,是Http Components下的一個組件。

官網地址:http://hc.apache.org/index.html

特色:

  • 基於標準、純淨的Java語言。實現了Http1.0和Http1.1
  • 以可擴展的面向對象的結構實現了Http所有的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)
  • 支持HTTPS協議。
  • 經過Http代理創建透明的鏈接。
  • 自動處理Set-Cookie中的Cookie。

3.1.2.使用

咱們導入課前資料提供的demo工程:《http-demo》

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">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.leyou.demo</groupId>
    <artifactId>http-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>http-demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!--核心依賴,包括auto-configuration , logging等-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- springboot測試模塊的起步依賴 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- http客戶端工具,個性化實現對請求和響應的處理 -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.10</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


</project>
http-demo 的pom.xml

 

HttpTests

package com.leyou.httpdemo; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.junit.Before; import org.junit.Test; import java.io.IOException; public class HttpTests { CloseableHttpClient httpClient; @Before //初始化
    public void init() { httpClient = HttpClients.createDefault(); } @Test public void testGet() throws IOException { //發起get請求
        HttpGet request = new HttpGet("http://www.baidu.com"); String response = this.httpClient.execute(request, new BasicResponseHandler()); System.out.println(response); } @Test public void testPost() throws IOException { //發起Post請求
        HttpGet request = new HttpGet("http://www.oschina.net/"); request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"); String response = this.httpClient.execute(request, new BasicResponseHandler()); System.out.println(response); } //==========我是一個分割線============//  }

 

若是想要獲得對象,咱們還須要手動進行Json反序列化,這一點比較麻煩。

3.1.3.Json轉換工具

HttpClient請求數據後是json字符串,須要咱們本身把Json字符串反序列化爲對象,可使用JacksonJson工具來實現。

JacksonJson是SpringMVC內置的json處理工具,其中有一個ObjectMapper,能夠方便的實現對json的處理:

 對象轉json

// json處理工具
    private ObjectMapper mapper = new ObjectMapper();  // 成員變量
 @Test public void testJson() throws JsonProcessingException { User user = new User();  // 局部變量
        user.setId(8L); user.setAge(21); user.setName("柳巖"); user.setUserName("liuyan"); // 序列化
        String json = mapper.writeValueAsString(user); System.out.println("json = " + json); }

 結果:

 

json轉普通對象

// json處理工具:json轉普通對象
    private ObjectMapper mapper = new ObjectMapper(); @Test public void testJson() throws IOException { User user = new User(); user.setId(8L); user.setAge(21); user.setName("柳巖"); user.setUserName("liuyan"); // 序列化
        String json = mapper.writeValueAsString(user); // 反序列化,接收兩個參數:json數據,反序列化的目標類字節碼
        User result = mapper.readValue(json, User.class); System.out.println("result = " + result); }

 結果: 

json轉集合

json轉集合相對比較麻煩,由於你沒法同時把集合的class和元素的class同時傳遞到那一個字節碼參數的位置。

所以Jackson作了一個類型工廠,用來解決這個問題:

// json處理工具:json轉集合
    private ObjectMapper mapper = new ObjectMapper(); @Test public void testJson() throws IOException { User user = new User(); user.setId(8L); user.setAge(21); user.setName("柳巖"); user.setUserName("liuyan"); // 序列化,獲得對象集合的json字符串
        String json = mapper.writeValueAsString(Arrays.asList(user, user)); // 反序列化,接收兩個參數:json數據,反序列化的目標類字節碼
        List<User> users = mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, User.class)); for (User u : users) { System.out.println("u = " + u); } }

json轉任意複雜類型

當對象泛型關係複雜時,類型工廠也很差使了。這個時候Jackson提供了TypeReference來接收類型泛型,而後底層經過反射來獲取泛型上的具體類型。實現數據轉換。

// json轉任意複雜類型
    private ObjectMapper mapper = new ObjectMapper(); @Test public void testJson() throws IOException { User user = new User(); user.setId(8L); user.setAge(21); user.setName("柳巖"); user.setUserName("liuyan"); Country country = new Country(); country.setId(2L); country.setCountryname("中國"); country.setCountrycode("+86"); // 序列化,獲得對象集合的json字符串
        String json = mapper.writeValueAsString(Arrays.asList(user, user)); System.out.println("json = " + json); System.out.println("=============="); // 反序列化,接收兩個參數:json數據,反序列化的目標類字節碼
        TypeReference ref = new TypeReference<List<User>>(){}; List<User> users = mapper.readValue(json, ref); for (User u : users) { System.out.println("u = " + u); } }

結果:


3.3.Spring的RestTemplate

 Spring提供了一個RestTemplate模板工具類,對基於Http的客戶端進行了封裝,而且實現了對象與json的序列化和反序列化,很是方便。RestTemplate並無限定Http的客戶端類型,而是進行了抽象,目前經常使用的3種都有支持:

  • HttpClient
  • OkHttp
  • JDK原生的URLConnection(默認的)

首先在項目中註冊一個RestTemplate對象,能夠在啓動類位置註冊:

@SpringBootApplication public class HttpDemoApplication { public static void main(String[] args) { SpringApplication.run(HttpDemoApplication.class, args); } @Bean public RestTemplate restTemplate() { // 默認的RestTemplate,底層是走JDK的URLConnection方式。
        return new RestTemplate(); } }

 

在測試類中直接@Autowired注入:  

import java.io.IOException; import java.util.Arrays; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest(classes = HttpDemoApplication.class) public class HttpDemoApplicationTests { @Autowired private RestTemplate restTemplate; @Test public void httpGet() { /*經過RestTemplate的getForObject()方法,傳遞url地址及實體類的字節碼, RestTemplate會自動發起請求,接收響應,而且幫咱們對響應結果進行反序列化。*/ User user = this.restTemplate.getForObject("http://localhost/hello", User.class); System.out.println(user); } //==============華麗的分割線==================//

 

 學習完了Http客戶端工具,接下來就能夠正式學習微服務了。

 day02-springcloud(理論篇中) 

  • 知道什麼是SpringCloud

 

================================================

參考資料:

關於SpringBoot中spring-boot-starter-*起步依賴參考指南

Gson、jackson 序列化,反序列化(單個、集合)

Jackson序列化和反序列化

關於jackson 序列化反序列化屬性名稱問題

end

相關文章
相關標籤/搜索