1. 程式人生 > >跟我學SpringCloud | 第二十章:Spring Cloud 之 okhttp

跟我學SpringCloud | 第二十章:Spring Cloud 之 okhttp

1. 什麼是 okhttp ?

okhttp 是由 square 公司開源的一個 http 客戶端。在 Java 平臺上,Java 標準庫提供了 HttpURLConnection 類來支援 HTTP 通訊。不過 HttpURLConnection 本身的 API 不夠友好,所提供的功能也有限。大部分 Java 程式都選擇使用 Apache 的開源專案 HttpClient 作為 HTTP 客戶端。Apache HttpClient 庫的功能強大,使用率也很高。

2. 為什麼要使用 okhttp ?

okhttp 的設計初衷就是簡單和高效,這也是我們選擇它的重要原因之一。它的優勢如下:

  • 支援 HTTP/2 協議。
  • 允許連線到同一個主機地址的所有請求,提高請求效率。
  • 共享Socket,減少對伺服器的請求次數。
  • 通過連線池,減少了請求延遲。
  • 快取響應資料來減少重複的網路請求。
  • 減少了對資料流量的消耗。
  • 自動處理GZip壓縮。

3. 實戰目標

  • Feign 中使用 okhttp 替代 httpclient
  • Zuul 中使用 okhttp 替代 httpclient

4. 在 Feign 中使用 okhttp

首先介紹一下工程結構,本演示工程包含 provider-server、consumer-server、eureka-server 和 zuul-server 。

4.1 consumer-server 依賴 pom.xml 如下:

程式碼清單:chapter19/consumer-server/pom.xml
***

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    <dependency>
        <groupId>io.github.openfeign</groupId>
        <artifactId>feign-okhttp</artifactId>
    </dependency>
</dependencies>
  • feign-okhttp 這裡無需指定版本,目前引入的 feign-okhttp 版本為 10.2.3 ,而 okhttp 的版本為 3.8.1 ,如圖:

4.2 配置檔案 application.yml

程式碼清單:chapter19/consumer-server/src/main/resources/application.yml
***

feign:
  httpclient:
    enabled: false
  okhttp:
    enabled: true
  • 在配置檔案中需關閉 feign 對 httpclient 的使用並開啟 okhttp 。

4.3 配置類 OkHttpConfig.java

程式碼清單:chapter19/consumer-server/src/main/java/com/springcloud/consumerserver/config/OkHttpConfig.java
***

@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class OkHttpConfig {

    @Bean
    public OkHttpClient okHttpClient(){
        return new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .connectionPool(new ConnectionPool(10 , 5L, TimeUnit.MINUTES))
                .addInterceptor(new OkHttpLogInterceptor())
                .build();
    }
}
  • 在配置類中將 OkHttpClient 注入 Spring 的容器中,這裡我們指定了連線池的大小,最大保持連線數為 10 ,並且在 5 分鐘不活動之後被清除。
  • 筆者這裡配置了一個 okhttp 的日誌攔截器。

4.4 日誌攔截器 OkHttpLogInterceptor.java

程式碼清單:
***

@Slf4j
public class OkHttpLogInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        log.info("OkHttpUrl : " + chain.request().url());
        return chain.proceed(chain.request());
    }
}
  • 這裡實現的介面是 okhttp3.Interceptor ,並不是 Spring Boot 中的 Interceptor。
  • 筆者這裡僅簡單列印了 okhttp 請求的路徑,如果有業務校驗許可權等需求可以放在攔截器中實現。

遠端 Feign 呼叫程式碼略過,有需要的讀者可以訪問 Github 倉庫獲取。

5. 在 Zuul 中使用 okhttp

5.1 pom.xml 加入 okhttp 依賴

程式碼清單:chapter19/zuul-server/pom.xml
***

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
</dependency>

5.2 配置檔案開啟 okhttp

程式碼清單:chapter19/zuul-server/src/main/resources/application.yml
***

ribbon:
  http:
    client:
      enabled: false
  okhttp:
    enabled: true
  • 因為 Zuul 的負載均衡實現是通過 Ribbon 實現的,所以 Http 客戶端的配置自然也是對 Ribbon 元件的配置。

6. 測試

我們修改 idea 啟動配置,分別在 8000 和 8001 埠啟動 provider-server ,並且順次啟動其餘工程,開啟瀏覽器訪問連結:http://localhost:8080/consumer/hello ,多次重新整理,可以看到 Hello Spring Cloud! Port : 8000Hello Spring Cloud! Port : 8001 交替書出現,可以證明負載均衡已經成功,可以檢視 consumer-server 的日誌,如下:

2019-09-23 23:15:27.097  INFO 10536 --- [nio-9000-exec-5] c.s.c.intercepter.OkHttpLogInterceptor   : OkHttpUrl : http://host.docker.internal:8001/hello
2019-09-23 23:15:27.593  INFO 10536 --- [nio-9000-exec-6] c.s.c.intercepter.OkHttpLogInterceptor   : OkHttpUrl : http://host.docker.internal:8000/hello
2019-09-23 23:15:27.942  INFO 10536 --- [nio-9000-exec-7] c.s.c.intercepter.OkHttpLogInterceptor   : OkHttpUrl : http://host.docker.internal:8001/hello
2019-09-23 23:15:28.251  INFO 10536 --- [nio-9000-exec-9] c.s.c.intercepter.OkHttpLogInterceptor   : OkHttpUrl : http://host.docker.internal:8000/hello
2019-09-23 23:15:47.877  INFO 10536 --- [nio-9000-exec-8] c.s.c.intercepter.OkHttpLogInterceptor   : OkHttpUrl : http://host.docker.internal:8001/hello

可以看到我們剛才自定義的日誌正常列印,證明現在訪問確實是通過 okhttp 來進行訪問的。

7. 示例程式碼

示例程式碼-Github

示例程式碼-Gi