2016-09-22 97 views
4

非常簡單的設置:春RestTemplate&AsyncRestTemplate與Netty4掛起永遠

的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.example</groupId> 
    <artifactId>demo-rest-client</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>jar</packaging> 

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

    <parent> 
     <groupId>org.springframework.boot</groupId> 
     <artifactId>spring-boot-starter-parent</artifactId> 
     <version>1.4.1.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> 
     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-web</artifactId> 
     </dependency> 
     <dependency> 
      <groupId>io.netty</groupId> 
      <artifactId>netty-all</artifactId> 
      <version>4.1.5.Final</version> 
     </dependency> 
     <dependency> 
      <groupId>io.netty</groupId> 
      <artifactId>netty-buffer</artifactId> 
      <version>4.1.5.Final</version> 
     </dependency> 
     <dependency> 
      <groupId>com.squareup.okhttp3</groupId> 
      <artifactId>okhttp</artifactId> 
      <version>3.4.1</version> 
     </dependency> 
     <dependency> 
      <groupId>io.github.openfeign</groupId> 
      <artifactId>feign-core</artifactId> 
      <version>9.3.1</version> 
     </dependency> 
     <dependency> 
      <groupId>io.github.openfeign</groupId> 
      <artifactId>feign-hystrix</artifactId> 
      <version>9.3.1</version> 
     </dependency> 

     <dependency> 
      <groupId>org.springframework.boot</groupId> 
      <artifactId>spring-boot-starter-test</artifactId> 
      <scope>test</scope> 
     </dependency> 
    </dependencies> 

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

</project> 

和測試案例來證明AsyncRestTemplate的不同用途:

SampleTests.java

package com.example; 

import com.netflix.hystrix.HystrixCommand; 
import com.netflix.hystrix.HystrixCommandProperties; 
import feign.RequestLine; 
import feign.hystrix.HystrixFeign; 
import feign.hystrix.SetterFactory; 
import org.junit.Test; 
import org.springframework.http.ResponseEntity; 
import org.springframework.http.client.Netty4ClientHttpRequestFactory; 
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory; 
import org.springframework.util.concurrent.ListenableFuture; 
import org.springframework.web.client.AsyncRestTemplate; 
import org.springframework.web.client.RestTemplate; 

public class SampleTests { 

    private static final String URL = "https://api.github.com/users/octocat"; 
    private static final int DEFAULT_SLEEP_MILLIS = 20; 
    private static final int DEFAULT_TIMEOUT = 10000; 

    @Test(timeout = DEFAULT_TIMEOUT) 
    public void syncRestNetty() throws Exception { 
     RestTemplate restTemplate = new RestTemplate(new Netty4ClientHttpRequestFactory()); 
     ResponseEntity<String> response = restTemplate.getForEntity(URL, String.class); 
     System.out.println("response = " + response); 
    } 

    @Test(timeout = DEFAULT_TIMEOUT) 
    public void asyncRestNetty() throws Exception { 
     AsyncRestTemplate restTemplate = new AsyncRestTemplate(new Netty4ClientHttpRequestFactory()); 
     ListenableFuture<ResponseEntity<String>> listenableFuture = restTemplate.getForEntity(URL, String.class); 
     listenableFuture.addCallback(result -> System.out.println("result = " + result), Throwable::printStackTrace); 
     while (!listenableFuture.isDone()) { 
      Thread.sleep(DEFAULT_SLEEP_MILLIS); 
     } 
     System.out.println("the end"); 
    } 

    @Test 
    public void asyncRestOkHttp() throws Exception { 
     AsyncRestTemplate restTemplate = new AsyncRestTemplate(new OkHttp3ClientHttpRequestFactory()); 
     ListenableFuture<ResponseEntity<String>> listenableFuture = restTemplate.getForEntity(URL, String.class); 
     listenableFuture.addCallback(result -> System.out.println("result = " + result), Throwable::printStackTrace); 
     while (!listenableFuture.isDone()) { 
      Thread.sleep(DEFAULT_SLEEP_MILLIS); 
     } 
     System.out.println("the end"); 
    } 

    @Test 
    public void asyncRestHystrixFeign() throws Exception { 
     GitHub gitHub = HystrixFeign.builder() 
       .setterFactory((target, method) -> new SetterFactory.Default().create(target, method).andCommandPropertiesDefaults(HystrixCommandProperties.defaultSetter().withExecutionTimeoutInMilliseconds(10000))) 
       .target(GitHub.class, "https://api.github.com"); 
     HystrixCommand<String> command = gitHub.octocatAsync(); 
     command.toObservable().subscribe(result -> System.out.println("result = " + result), Throwable::printStackTrace); 
     while (!command.isExecutionComplete()) { 
      Thread.sleep(DEFAULT_SLEEP_MILLIS); 
     } 
     System.out.println("command.getExecutionTimeInMilliseconds() = " + command.getExecutionTimeInMilliseconds()); 
     System.out.println("the end"); 
    } 

    interface GitHub { 
     @RequestLine("GET /users/octocat") 
     HystrixCommand<String> octocatAsync(); 
    } 
} 

當試圖運行使用Netty的測試時,它們會永遠掛起。 (爲了看到這個,請刪除JUnit超時限制)。但是,如果我運行與其他客戶端完全相同的代碼,一切都按預期工作。

我嘗試過不同版本的Spring Boot和Netty,但沒有成功。從日誌中看,一切都很好。

我在這裏錯過了什麼?

編輯: 開了票https://jira.spring.io/browse/SPR-14744春的Gitter的建議

EDIT 2:從布賴恩Clozel 回答幫我找到了這是關係到了Netty沒有意識到服務器發送一個空響應的問題(一個特定的Github API和純http的情況下),所以我將其標記爲已接受。

回答

1

您可以嘗試使用Netty Sslcontext配置您的請求工廠嗎?

Netty4ClientHttpRequestFactory nettyFactory = new Netty4ClientHttpRequestFactory(); 
nettyFactory.setSslContext(SslContextBuilder.forClient().build()); 
AsyncRestTemplate restTemplate = new AsyncRestTemplate(nettyFactory); 

沒有這個上下文,客戶端正在試圖發送純文本請求到https端點;在這種情況下,您可能會收到HTTP 400響應。

在您的示例代碼中,throwable應該是HttpClientErrorException的實例,並且您可以通過記錄響應狀態或其身體exception.getResponseBodyAsString()來獲取該信息。