servicecomb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From GitBox <...@apache.org>
Subject [GitHub] wujimin closed pull request #594: [SCB-379] support AsyncRestTemplate
Date Wed, 04 Apr 2018 07:45:57 GMT
wujimin closed pull request #594: [SCB-379] support AsyncRestTemplate
URL: https://github.com/apache/incubator-servicecomb-java-chassis/pull/594
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/integration-tests/springmvc-tests/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java b/integration-tests/springmvc-tests/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java
index 1d2e1baa8..a00dbbe9d 100644
--- a/integration-tests/springmvc-tests/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java
+++ b/integration-tests/springmvc-tests/src/test/java/org/apache/servicecomb/demo/springmvc/tests/SpringMvcIntegrationTestBase.java
@@ -50,6 +50,7 @@
 import org.apache.servicecomb.demo.compute.Person;
 import org.apache.servicecomb.demo.server.User;
 import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
+import org.apache.servicecomb.provider.springmvc.reference.async.CseAsyncRestTemplate;
 import org.junit.ClassRule;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -65,6 +66,9 @@
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
+import org.springframework.util.concurrent.ListenableFuture;
+import org.springframework.util.concurrent.ListenableFutureCallback;
+import org.springframework.web.client.AsyncRestTemplate;
 import org.springframework.web.client.RestClientException;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.client.UnknownHttpStatusCodeException;
@@ -78,6 +82,8 @@
 
   private final RestTemplate restTemplate = new RestTemplate();
 
+  private final AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
+
   private final String codeFirstUrl = baseUrl + "codeFirstSpringmvc/";
 
   private final String controllerUrl = baseUrl + "springmvc/controller/";
@@ -85,11 +91,12 @@
   static void setUpLocalRegistry() {
     ClassLoader loader = Thread.currentThread().getContextClassLoader();
     URL resource = loader.getResource("registry.yaml");
+    assert resource != null;
     System.setProperty(LOCAL_REGISTRY_FILE_KEY, resource.getPath());
   }
 
   @Test
-  public void ableToQueryAtRootBasePath() {
+  public void ableToQueryAtRootBasePath() throws Exception {
     ResponseEntity<String> responseEntity = restTemplate
         .getForEntity(baseUrl + "sayHi?name=Mike", String.class);
 
@@ -101,28 +108,51 @@ public void ableToQueryAtRootBasePath() {
 
     assertThat(responseEntity.getStatusCode(), is(OK));
     assertThat(responseEntity.getBody(), is("Hi 小 强"));
+
+    //integration test for AsyncRestTemplate
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .getForEntity(baseUrl + "sayHi?name=Mike", String.class);
+    ResponseEntity<String> futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getStatusCode(), is(OK));
+    assertThat(futureResponse.getBody(), is("Hi Mike"));
+
+    listenableFuture = asyncRestTemplate.getForEntity(baseUrl + "sayHi?name={name}", String.class, "小 强");
+    futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getStatusCode(), is(OK));
+    assertThat(futureResponse.getBody(), is("Hi 小 强"));
   }
 
   @Test
-  public void ableToQueryAtRootPath() {
+  public void ableToQueryAtRootPath() throws Exception {
     ResponseEntity<String> responseEntity = restTemplate
         .getForEntity(baseUrl, String.class);
 
     assertThat(responseEntity.getStatusCode(), is(OK));
     assertThat(responseEntity.getBody(), is("Welcome home"));
+
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate.getForEntity(baseUrl, String.class);
+    ResponseEntity<String> futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getStatusCode(), is(OK));
+    assertThat(futureResponse.getBody(), is("Welcome home"));
   }
 
   @Test
-  public void ableToQueryAtNonRootPath() {
+  public void ableToQueryAtNonRootPath() throws Exception {
     ResponseEntity<String> responseEntity = restTemplate
         .getForEntity(baseUrl + "french/bonjour?name=Mike", String.class);
 
     assertThat(responseEntity.getStatusCode(), is(OK));
     assertThat(responseEntity.getBody(), is("Bonjour Mike"));
+
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .getForEntity(baseUrl + "french/bonjour?name=Mike", String.class);
+    ResponseEntity<String> futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getStatusCode(), is(OK));
+    assertThat(futureResponse.getBody(), is("Bonjour Mike"));
   }
 
   @Test
-  public void ableToPostMap() {
+  public void ableToPostMap() throws Exception {
     Map<String, User> users = new HashMap<>();
     users.put("user1", userOfNames("name11", "name12"));
     users.put("user2", userOfNames("name21", "name22"));
@@ -139,6 +169,17 @@ public void ableToPostMap() {
     Map<String, User> body = responseEntity.getBody();
     assertArrayEquals(body.get("user1").getNames(), new String[] {"name11", "name12"});
     assertArrayEquals(body.get("user2").getNames(), new String[] {"name21", "name22"});
+
+    ListenableFuture<ResponseEntity<Map<String, User>>> listenableFuture = asyncRestTemplate
+        .exchange(codeFirstUrl + "testUserMap",
+            POST,
+            jsonRequest(users),
+            reference);
+    ResponseEntity<Map<String, User>> futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getStatusCode(), is(OK));
+    body = futureResponse.getBody();
+    assertArrayEquals(body.get("user1").getNames(), new String[] {"name11", "name12"});
+    assertArrayEquals(body.get("user2").getNames(), new String[] {"name21", "name22"});
   }
 
   private User userOfNames(String... names) {
@@ -148,19 +189,24 @@ private User userOfNames(String... names) {
   }
 
   @Test
-  public void ableToConsumeTextPlain() {
+  public void ableToConsumeTextPlain() throws Exception {
     String body = "a=1";
-
     String result = restTemplate.postForObject(
         codeFirstUrl + "textPlain",
         body,
         String.class);
 
     assertThat(jsonOf(result, String.class), is(body));
+
+    HttpEntity<?> entity = new HttpEntity<>(body);
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .postForEntity(codeFirstUrl + "textPlain", entity, String.class);
+    ResponseEntity<String> responseEntity = listenableFuture.get();
+    assertThat(jsonOf(responseEntity.getBody(), String.class), is(body));
   }
 
   @Test
-  public void ableToPostBytes() throws IOException {
+  public void ableToPostBytes() throws Exception {
     byte[] body = new byte[] {0, 1, 2};
 
     byte[] result = restTemplate.postForObject(
@@ -174,10 +220,21 @@ public void ableToPostBytes() throws IOException {
     assertEquals(1, result[1]);
     assertEquals(2, result[2]);
     assertEquals(3, result.length);
+
+    ListenableFuture<ResponseEntity<byte[]>> listenableFuture = asyncRestTemplate
+        .postForEntity(codeFirstUrl + "bytes",
+            jsonRequest(RestObjectMapper.INSTANCE.writeValueAsBytes(body)),
+            byte[].class);
+    ResponseEntity<byte[]> responseEntity = listenableFuture.get();
+    result = RestObjectMapper.INSTANCE.readValue(responseEntity.getBody(), byte[].class);
+    assertEquals(1, result[0]);
+    assertEquals(1, result[1]);
+    assertEquals(2, result[2]);
+    assertEquals(3, result.length);
   }
 
   @Test
-  public void ableToUploadFile() throws IOException {
+  public void ableToUploadFile() throws Exception {
     String file1Content = "hello world";
     String file2Content = "bonjour";
     String username = "mike";
@@ -195,10 +252,17 @@ public void ableToUploadFile() throws IOException {
         String.class);
 
     assertThat(result, is(file1Content + file2Content + username));
+
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .postForEntity(codeFirstUrl + "upload",
+            new HttpEntity<>(map, headers),
+            String.class);
+    ResponseEntity<String> responseEntity = listenableFuture.get();
+    assertThat(responseEntity.getBody(), is(file1Content + file2Content + username));
   }
 
   @Test
-  public void ableToUploadFileFromConsumer() throws IOException {
+  public void ableToUploadFileFromConsumer() throws Exception {
     String file1Content = "hello world";
     String file2Content = "bonjour";
     String username = "mike";
@@ -216,10 +280,17 @@ public void ableToUploadFileFromConsumer() throws IOException {
         String.class);
 
     assertThat(result, is(file1Content + file2Content + username));
+    AsyncRestTemplate cseAsyncRestTemplate = new CseAsyncRestTemplate();
+    ListenableFuture<ResponseEntity<String>> listenableFuture = cseAsyncRestTemplate
+        .postForEntity("cse://springmvc-tests/codeFirstSpringmvc/upload",
+            new HttpEntity<>(map, headers),
+            String.class);
+    ResponseEntity<String> responseEntity = listenableFuture.get();
+    assertThat(responseEntity.getBody(), is(file1Content + file2Content + username));
   }
 
   @Test
-  public void ableToUploadFileWithoutAnnotation() throws IOException {
+  public void ableToUploadFileWithoutAnnotation() throws Exception {
     String file1Content = "hello world";
     String file2Content = "bonjour";
     String username = "mike";
@@ -237,10 +308,17 @@ public void ableToUploadFileWithoutAnnotation() throws IOException {
         String.class);
 
     assertThat(result, is(file1Content + file2Content + username));
+
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .postForEntity(codeFirstUrl + "uploadWithoutAnnotation",
+            new HttpEntity<>(map, headers),
+            String.class);
+    ResponseEntity<String> responseEntity = listenableFuture.get();
+    assertThat(responseEntity.getBody(), is(file1Content + file2Content + username));
   }
 
   @Test
-  public void blowsUpWhenFileNameDoesNotMatch() throws IOException {
+  public void blowsUpWhenFileNameDoesNotMatch() throws Exception {
     String file1Content = "hello world";
     String file2Content = "bonjour";
 
@@ -277,44 +355,71 @@ public void ableToPostDate() throws Exception {
         seconds);
 
     assertThat(result, is(Date.from(date.plusSeconds(seconds).toInstant())));
+
+    ListenableFuture<ResponseEntity<Date>> listenableFuture = asyncRestTemplate
+        .postForEntity(codeFirstUrl + "addDate?seconds={seconds}",
+            new HttpEntity<>(body, headers),
+            Date.class,
+            seconds);
+    ResponseEntity<Date> dateResponseEntity = listenableFuture.get();
+    assertThat(dateResponseEntity.getBody(), is(Date.from(date.plusSeconds(seconds).toInstant())));
   }
 
   @Test
-  public void ableToDeleteWithQueryString() {
+  public void ableToDeleteWithQueryString() throws Exception {
     ResponseEntity<String> responseEntity = restTemplate.exchange(codeFirstUrl + "addstring?s=a&s=b",
         HttpMethod.DELETE,
         null,
         String.class);
 
     assertThat(responseEntity.getBody(), is("ab"));
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .exchange(codeFirstUrl + "addstring?s=a&s=b", HttpMethod.DELETE, null, String.class);
+    ResponseEntity<String> futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getBody(), is("ab"));
   }
 
   @Test
-  public void ableToGetBoolean() {
+  public void ableToGetBoolean() throws Exception {
     boolean result = restTemplate.getForObject(codeFirstUrl + "istrue", boolean.class);
 
     assertThat(result, is(true));
+
+    ListenableFuture<ResponseEntity<Boolean>> listenableFuture = asyncRestTemplate
+        .getForEntity(codeFirstUrl + "istrue", boolean.class);
+    ResponseEntity<Boolean> futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getBody(), is(true));
   }
 
   @Test
-  public void putsEndWithPathParam() {
+  public void putsEndWithPathParam() throws Exception {
     ResponseEntity<String> responseEntity = restTemplate
         .exchange(codeFirstUrl + "sayhi/{name}", PUT, null, String.class, "world");
 
     assertThat(responseEntity.getStatusCode(), is(ACCEPTED));
     assertThat(jsonOf(responseEntity.getBody(), String.class), is("world sayhi"));
+
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .exchange(codeFirstUrl + "sayhi/{name}", PUT, null, String.class, "world");
+    ResponseEntity<String> futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getStatusCode(), is(ACCEPTED));
+    assertThat(jsonOf(futureResponse.getBody(), String.class), is("world sayhi"));
   }
 
   @Test
-  public void putsContainingPathParam() {
+  public void putsContainingPathParam() throws Exception {
     ResponseEntity<String> responseEntity = restTemplate
         .exchange(codeFirstUrl + "sayhi/{name}/v2", PUT, null, String.class, "world");
 
     assertThat(jsonOf(responseEntity.getBody(), String.class), is("world sayhi 2"));
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .exchange(codeFirstUrl + "sayhi/{name}/v2", PUT, null, String.class, "world");
+    responseEntity = listenableFuture.get();
+    assertThat(jsonOf(responseEntity.getBody(), String.class), is("world sayhi 2"));
   }
 
   @Test
-  public void ableToPostWithHeader() {
+  public void ableToPostWithHeader() throws Exception {
     Person person = new Person();
     person.setName("person name");
 
@@ -327,10 +432,15 @@ public void ableToPostWithHeader() {
         .postForEntity(codeFirstUrl + "saysomething", requestEntity, String.class);
 
     assertThat(jsonOf(responseEntity.getBody(), String.class), is("prefix  prefix person name"));
+
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .postForEntity(codeFirstUrl + "saysomething", requestEntity, String.class);
+    responseEntity = listenableFuture.get();
+    assertThat(jsonOf(responseEntity.getBody(), String.class), is("prefix  prefix person name"));
   }
 
   @Test
-  public void ableToPostObjectAsJson() {
+  public void ableToPostObjectAsJson() throws Exception {
     Map<String, String> personFieldMap = new HashMap<>();
     personFieldMap.put("name", "person name from map");
 
@@ -343,10 +453,21 @@ public void ableToPostObjectAsJson() {
     person = restTemplate.postForObject(codeFirstUrl + "sayhello", jsonRequest(input), Person.class);
 
     assertThat(person.toString(), is("hello person name from Object"));
+
+    ListenableFuture<ResponseEntity<Person>> listenableFuture = asyncRestTemplate
+        .postForEntity(codeFirstUrl + "sayhello", jsonRequest(personFieldMap), Person.class);
+    ResponseEntity<Person> futureResponse = listenableFuture.get();
+    person = futureResponse.getBody();
+    assertThat(person.toString(), is("hello person name from map"));
+
+    listenableFuture = asyncRestTemplate.postForEntity(codeFirstUrl + "sayhello", jsonRequest(input), Person.class);
+    futureResponse = listenableFuture.get();
+    person = futureResponse.getBody();
+    assertThat(person.toString(), is("hello person name from Object"));
   }
 
   @Test
-  public void ableToPostForm() {
+  public void ableToPostForm() throws Exception {
     MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
     params.add("a", "5");
     params.add("b", "3");
@@ -357,10 +478,15 @@ public void ableToPostForm() {
         .postForObject(codeFirstUrl + "add", new HttpEntity<>(params, headers), Integer.class);
 
     assertThat(result, is(8));
+
+    ListenableFuture<ResponseEntity<Integer>> listenableFuture = asyncRestTemplate
+        .postForEntity(codeFirstUrl + "add", new HttpEntity<>(params, headers), Integer.class);
+    ResponseEntity<Integer> futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getBody(), is(8));
   }
 
   @Test
-  public void ableToExchangeCookie() {
+  public void ableToExchangeCookie() throws Exception {
     Map<String, String> params = new HashMap<>();
     params.put("a", "5");
 
@@ -376,10 +502,20 @@ public void ableToExchangeCookie() {
         params);
 
     assertThat(result.getBody(), is(2));
+
+    ListenableFuture<ResponseEntity<Integer>> listenableFuture = asyncRestTemplate
+        .exchange(codeFirstUrl + "reduce?a={a}",
+            GET,
+            requestEntity,
+            Integer.class,
+            params);
+    result = listenableFuture.get();
+    assertThat(result.getBody(), is(2));
+
   }
 
   @Test
-  public void getsEndWithRequestVariables() {
+  public void getsEndWithRequestVariables() throws Exception {
     int result = restTemplate.getForObject(
         controllerUrl + "add?a={a}&b={b}",
         Integer.class,
@@ -387,10 +523,17 @@ public void getsEndWithRequestVariables() {
         4);
 
     assertThat(result, is(7));
+    ListenableFuture<ResponseEntity<Integer>> listenableFuture = asyncRestTemplate
+        .getForEntity(controllerUrl + "add?a={a}&b={b}",
+            Integer.class,
+            3,
+            4);
+    ResponseEntity<Integer> futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getBody(), is(7));
   }
 
   @Test
-  public void postsEndWithPathParam() {
+  public void postsEndWithPathParam() throws Exception {
     String result = restTemplate.postForObject(
         controllerUrl + "sayhello/{name}",
         null,
@@ -411,10 +554,26 @@ public void postsEndWithPathParam() {
 
     assertThat(result, is("hello 中 国"));
     restTemplate.setMessageConverters(convertersOld);
+
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .postForEntity(controllerUrl + "sayhello/{name}",
+            null,
+            String.class,
+            "world");
+    ResponseEntity<String> futureResonse = listenableFuture.get();
+    assertThat(jsonOf(futureResonse.getBody(), String.class), is("hello world"));
+    asyncRestTemplate.setMessageConverters(converters);
+    listenableFuture = asyncRestTemplate.postForEntity(controllerUrl + "sayhello/{name}",
+        null,
+        String.class,
+        "中 国");
+    futureResonse = listenableFuture.get();
+    assertThat(futureResonse.getBody(), is("hello 中 国"));
+    asyncRestTemplate.setMessageConverters(convertersOld);
   }
 
   @Test
-  public void ableToPostObjectAsJsonWithRequestVariable() {
+  public void ableToPostObjectAsJsonWithRequestVariable() throws Exception {
     Person input = new Person();
     input.setName("world");
 
@@ -441,15 +600,39 @@ public void ableToPostObjectAsJsonWithRequestVariable() {
 
     assertThat(result, is("hello 中国"));
     restTemplate.setMessageConverters(convertersOld);
+
+    input.setName("world");
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .postForEntity(controllerUrl + "saysomething?prefix={prefix}",
+            jsonRequest(input),
+            String.class,
+            "hello");
+    ResponseEntity<String> futureResponse = listenableFuture.get();
+    assertThat(jsonOf(futureResponse.getBody(), String.class), is("hello world"));
+
+    asyncRestTemplate.setMessageConverters(converters);
+    input.setName("中国");
+    listenableFuture = asyncRestTemplate.postForEntity(controllerUrl + "saysomething?prefix={prefix}",
+        jsonRequest(input),
+        String.class,
+        "hello");
+    futureResponse = listenableFuture.get();
+    assertThat(futureResponse.getBody(), is("hello 中国"));
+    asyncRestTemplate.setMessageConverters(convertersOld);
   }
 
   @Test
-  public void ensureServerWorksFine() {
+  public void ensureServerWorksFine() throws Exception {
     String result = restTemplate.getForObject(
         controllerUrl + "sayhi?name=world",
         String.class);
 
     assertThat(jsonOf(result, String.class), is("hi world [world]"));
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate
+        .getForEntity(controllerUrl + "sayhi?name=world",
+            String.class);
+    ResponseEntity<String> futureResponse = listenableFuture.get();
+    assertThat(jsonOf(futureResponse.getBody(), String.class), is("hi world [world]"));
   }
 
   @Test
@@ -477,6 +660,25 @@ public void ableToSetCustomHeader() {
         String.class);
 
     assertThat(jsonOf(result.getBody(), String.class), is("hei world"));
+
+    ListenableFuture<ResponseEntity<String>> listenableFuture = asyncRestTemplate.exchange(controllerUrl + "sayhei",
+        GET,
+        requestEntity,
+        String.class);
+//    ResponseEntity<String> responseEntity = listenableFuture.get();
+    listenableFuture.addCallback(
+        new ListenableFutureCallback<ResponseEntity<String>>() {
+          @Override
+          public void onFailure(Throwable ex) {
+          }
+
+          @Override
+          public void onSuccess(ResponseEntity<String> result) {
+            assertThat(jsonOf(result.getBody(), String.class), is("hei world"));
+          }
+        }
+    );
+
   }
 
   private <T> HttpEntity<T> jsonRequest(T body) {
diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpRequest.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpRequest.java
index 2ff0ca571..947469d3d 100644
--- a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpRequest.java
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/CseClientHttpRequest.java
@@ -17,7 +17,6 @@
 
 package org.apache.servicecomb.provider.springmvc.reference;
 
-import java.io.IOException;
 import java.io.OutputStream;
 import java.net.URI;
 import java.util.List;
@@ -73,6 +72,34 @@ public CseClientHttpRequest(URI uri, HttpMethod method) {
     this.method = method;
   }
 
+  public String getPath() {
+    return path;
+  }
+
+  public void setPath(String path) {
+    this.path = path;
+  }
+
+  protected RequestMeta getRequestMeta() {
+    return requestMeta;
+  }
+
+  protected void setRequestMeta(RequestMeta requestMeta) {
+    this.requestMeta = requestMeta;
+  }
+
+  public void setUri(URI uri) {
+    this.uri = uri;
+  }
+
+  public void setMethod(HttpMethod method) {
+    this.method = method;
+  }
+
+  protected void setQueryParams(Map<String, List<String>> queryParams) {
+    this.queryParams = queryParams;
+  }
+
   public InvocationContext getContext() {
     return context;
   }
@@ -101,12 +128,12 @@ public HttpHeaders getHeaders() {
   }
 
   @Override
-  public OutputStream getBody() throws IOException {
+  public OutputStream getBody() {
     return null;
   }
 
   @Override
-  public ClientHttpResponse execute() throws IOException {
+  public ClientHttpResponse execute() {
     path = findUriPath(uri);
     requestMeta = createRequestMeta(method.name(), uri);
 
@@ -119,7 +146,7 @@ public ClientHttpResponse execute() throws IOException {
     return this.invoke(args);
   }
 
-  private RequestMeta createRequestMeta(String httpMetod, URI uri) {
+  protected RequestMeta createRequestMeta(String httpMetod, URI uri) {
     String microserviceName = uri.getAuthority();
     ReferenceConfig referenceConfig = ReferenceConfigUtils.getForInvoke(microserviceName);
 
@@ -142,7 +169,7 @@ protected String findUriPath(URI uri) {
     return uri.getRawPath();
   }
 
-  private CseClientHttpResponse invoke(Object[] args) {
+  protected Invocation prepareInvocation(Object[] args) {
     Invocation invocation =
         InvocationFactory.forConsumer(requestMeta.getReferenceConfig(),
             requestMeta.getOperationMeta(),
@@ -153,22 +180,26 @@ private CseClientHttpResponse invoke(Object[] args) {
     if (context != null) {
       invocation.addContext(context);
     }
-
     invocation.getHandlerContext().put(RestConst.CONSUMER_HEADER, httpHeaders);
+    return invocation;
+  }
+
+  private CseClientHttpResponse invoke(Object[] args) {
+    Invocation invocation = prepareInvocation(args);
     Response response = doInvoke(invocation);
 
     if (response.isSuccessed()) {
       return new CseClientHttpResponse(response);
     }
 
-    throw ExceptionFactory.convertConsumerException((Throwable) response.getResult());
+    throw ExceptionFactory.convertConsumerException(response.getResult());
   }
 
   protected Response doInvoke(Invocation invocation) {
     return InvokerUtils.innerSyncInvoke(invocation);
   }
 
-  private Object[] collectArguments() {
+  protected Object[] collectArguments() {
     HttpServletRequest mockRequest = new CommonToHttpServletRequest(requestMeta.getPathParams(), queryParams,
         httpHeaders, requestBody, requestMeta.getSwaggerRestOperation().isFormData());
     return RestCodec.restToArgs(mockRequest, requestMeta.getSwaggerRestOperation());
diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequest.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequest.java
new file mode 100644
index 000000000..1be86dc88
--- /dev/null
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.provider.springmvc.reference.async;
+
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.concurrent.CompletableFuture;
+
+import org.apache.servicecomb.common.rest.RestConst;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.provider.consumer.InvokerUtils;
+import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpRequest;
+import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpResponse;
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.client.AsyncClientHttpRequest;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.util.concurrent.CompletableToListenableFutureAdapter;
+import org.springframework.util.concurrent.ListenableFuture;
+
+import io.netty.handler.codec.http.QueryStringDecoder;
+
+public class CseAsyncClientHttpRequest extends CseClientHttpRequest implements AsyncClientHttpRequest {
+
+  CseAsyncClientHttpRequest() {
+  }
+
+  CseAsyncClientHttpRequest(URI uri, HttpMethod method) {
+    this.setUri(uri);
+    this.setMethod(method);
+  }
+
+  @Override
+  public OutputStream getBody() {
+    return null;
+  }
+
+  @SuppressWarnings("unchecked")
+  private ListenableFuture<ClientHttpResponse> invoke(Object[] args) {
+    Invocation invocation = prepareInvocation(args);
+    invocation.getHandlerContext().put(RestConst.CONSUMER_HEADER, this.getHeaders());
+    CompletableFuture<ClientHttpResponse> clientHttpResponseCompletableFuture = doAsyncInvoke(invocation);
+    return new CompletableToListenableFutureAdapter(clientHttpResponseCompletableFuture);
+  }
+
+  protected CompletableFuture<ClientHttpResponse> doAsyncInvoke(Invocation invocation) {
+    CompletableFuture<ClientHttpResponse> completableFuture = new CompletableFuture<>();
+    InvokerUtils.reactiveInvoke(invocation, (Response response) -> {
+      if (response.isSuccessed()) {
+        completableFuture.complete(new CseClientHttpResponse(response));
+      } else {
+        completableFuture.completeExceptionally(response.getResult());
+      }
+    });
+    return completableFuture;
+  }
+
+
+  @Override
+  public ListenableFuture<ClientHttpResponse> executeAsync() {
+    this.setPath(findUriPath(this.getURI()));
+    this.setRequestMeta(createRequestMeta(this.getMethod().name(), this.getURI()));
+    QueryStringDecoder queryStringDecoder = new QueryStringDecoder(this.getURI().getRawSchemeSpecificPart());
+    this.setQueryParams(queryStringDecoder.parameters());
+    Object[] args = this.collectArguments();
+    return this.invoke(args);
+  }
+}
diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactory.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactory.java
new file mode 100644
index 000000000..d27cf78bb
--- /dev/null
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.provider.springmvc.reference.async;
+
+import java.net.URI;
+
+import org.springframework.http.HttpMethod;
+import org.springframework.http.client.AsyncClientHttpRequest;
+import org.springframework.http.client.AsyncClientHttpRequestFactory;
+
+public class CseAsyncClientHttpRequestFactory implements AsyncClientHttpRequestFactory {
+  @Override
+  public AsyncClientHttpRequest createAsyncRequest(URI uri, HttpMethod httpMethod) {
+    return new CseAsyncClientHttpRequest(uri, httpMethod);
+  }
+}
diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallback.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallback.java
new file mode 100644
index 000000000..1ca4b4c2a
--- /dev/null
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallback.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.provider.springmvc.reference.async;
+
+import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.client.AsyncClientHttpRequest;
+import org.springframework.web.client.AsyncRequestCallback;
+
+public class CseAsyncRequestCallback<T> implements AsyncRequestCallback {
+  private HttpEntity<T> requestBody;
+
+  CseAsyncRequestCallback(HttpEntity<T> requestBody) {
+    this.requestBody = requestBody;
+  }
+
+  @Override
+  public void doWithRequest(AsyncClientHttpRequest request) {
+    CseAsyncClientHttpRequest cseAsyncClientHttpRequest = (CseAsyncClientHttpRequest) request;
+    if (requestBody != null) {
+      cseAsyncClientHttpRequest.setRequestBody(requestBody.getBody());
+    }
+
+    if (!CseHttpEntity.class.isInstance(requestBody)) {
+      return;
+    }
+
+    CseAsyncClientHttpRequest req = (CseAsyncClientHttpRequest) request;
+    CseHttpEntity<?> entity = (CseHttpEntity<?>) requestBody;
+    req.setContext(entity.getContext());
+  }
+}
diff --git a/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java
new file mode 100644
index 000000000..6f16f997e
--- /dev/null
+++ b/providers/provider-springmvc/src/main/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplate.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.provider.springmvc.reference.async;
+
+import java.lang.reflect.Type;
+import java.util.Arrays;
+
+import org.apache.servicecomb.provider.springmvc.reference.CseUriTemplateHandler;
+import org.springframework.http.HttpEntity;
+import org.springframework.web.client.AsyncRequestCallback;
+import org.springframework.web.client.AsyncRestTemplate;
+import org.springframework.web.client.CseHttpMessageConverter;
+
+public class CseAsyncRestTemplate extends AsyncRestTemplate {
+  public CseAsyncRestTemplate() {
+    setMessageConverters(Arrays.asList(new CseHttpMessageConverter()));
+    setAsyncRequestFactory(new CseAsyncClientHttpRequestFactory());
+    setUriTemplateHandler(new CseUriTemplateHandler());
+  }
+
+  @Override
+  @SuppressWarnings("unchecked")
+  protected <T> AsyncRequestCallback httpEntityCallback(HttpEntity<T> requestBody) {
+    return new CseAsyncRequestCallback(requestBody);
+  }
+
+  @Override
+  @SuppressWarnings("unchecked")
+  protected <T> AsyncRequestCallback httpEntityCallback(HttpEntity<T> requestBody, Type responseType) {
+    return new CseAsyncRequestCallback(requestBody);
+  }
+}
\ No newline at end of file
diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactoryTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactoryTest.java
new file mode 100644
index 000000000..ce10009a0
--- /dev/null
+++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestFactoryTest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.provider.springmvc.reference.async;
+
+import java.net.URI;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.http.HttpMethod;
+
+public class CseAsyncClientHttpRequestFactoryTest {
+  @Test
+  public void testCseAsyncClientHttpRequestFactory() {
+    CseAsyncClientHttpRequestFactory cseAsyncClientHttpRequestFactory = new CseAsyncClientHttpRequestFactory();
+    Assert.assertEquals(HttpMethod.GET,
+        cseAsyncClientHttpRequestFactory.createAsyncRequest(URI.create("/test"), HttpMethod.GET).getMethod());
+  }
+}
\ No newline at end of file
diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java
new file mode 100644
index 000000000..4ae2bc703
--- /dev/null
+++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncClientHttpRequestTest.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.provider.springmvc.reference.async;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.concurrent.CompletableFuture;
+
+import javax.xml.ws.Holder;
+
+import org.apache.servicecomb.common.rest.RestEngineSchemaListener;
+import org.apache.servicecomb.core.BootListener;
+import org.apache.servicecomb.core.CseContext;
+import org.apache.servicecomb.core.Invocation;
+import org.apache.servicecomb.core.definition.SchemaMeta;
+import org.apache.servicecomb.core.provider.consumer.ReferenceConfigUtils;
+import org.apache.servicecomb.core.unittest.UnitTestMeta;
+import org.apache.servicecomb.provider.springmvc.reference.CseClientHttpResponse;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
+import org.apache.servicecomb.serviceregistry.ServiceRegistry;
+import org.apache.servicecomb.serviceregistry.registry.ServiceRegistryFactory;
+import org.apache.servicecomb.swagger.invocation.Response;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.util.concurrent.ListenableFuture;
+import org.springframework.util.concurrent.ListenableFutureCallback;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+public class CseAsyncClientHttpRequestTest {
+
+  @Before
+  public void setup() {
+    ReferenceConfigUtils.setReady(true);
+  }
+
+  @After
+  public void teardown() {
+    ReferenceConfigUtils.setReady(false);
+  }
+
+  @RequestMapping(path = "SpringmvcImpl")
+  static class SpringmvcImpl {
+    @RequestMapping(path = "/bytes", method = RequestMethod.POST)
+    public byte[] bytes(@RequestBody byte[] input) {
+      input[0] = (byte) (input[0] + 1);
+      return input;
+    }
+  }
+
+  @Test
+  public void testNotReady() {
+    String exceptionMessage = "System is not ready for remote calls. "
+        + "When beans are making remote calls in initialization, it's better to "
+        + "implement " + BootListener.class.getName() + " and do it after EventType.AFTER_REGISTRY.";
+    ReferenceConfigUtils.setReady(false);
+    CseAsyncClientHttpRequest clientHttpRequest = new CseAsyncClientHttpRequest(URI.create("cse://app:test/"),
+        HttpMethod.POST);
+    try {
+      clientHttpRequest.executeAsync();
+    } catch (IllegalStateException e) {
+      Assert.assertEquals(exceptionMessage, e.getMessage());
+    }
+  }
+
+  @Test
+  public void testNormal() {
+    ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal();
+    serviceRegistry.init();
+    RegistryUtils.setServiceRegistry(serviceRegistry);
+    UnitTestMeta meta = new UnitTestMeta();
+    CseContext.getInstance()
+        .getSchemaListenerManager()
+        .setSchemaListenerList(Arrays.asList(new RestEngineSchemaListener()));
+
+    SchemaMeta schemaMeta = meta.getOrCreateSchemaMeta(CseAsyncClientHttpRequestTest.SpringmvcImpl.class);
+    CseContext.getInstance().getSchemaListenerManager().notifySchemaListener(schemaMeta);
+
+    Holder<Invocation> holder = new Holder<>();
+    CseAsyncClientHttpRequest client =
+        new CseAsyncClientHttpRequest(URI.create(
+            "cse://app:test/" + CseAsyncClientHttpRequestTest.SpringmvcImpl.class.getSimpleName() + "/bytes"),
+            HttpMethod.POST) {
+          @Override
+          protected CompletableFuture<ClientHttpResponse> doAsyncInvoke(Invocation invocation) {
+            CompletableFuture<ClientHttpResponse> completableFuture = new CompletableFuture<>();
+            holder.value = invocation;
+            completableFuture.complete(new CseClientHttpResponse(Response.ok("result")));
+            return completableFuture;
+          }
+        };
+    byte[] body = "abc".getBytes();
+    client.setRequestBody(body);
+    client.executeAsync();
+    Assert.assertArrayEquals(body, holder.value.getSwaggerArgument(0));
+  }
+
+  @Test
+  public void testFail() {
+    ServiceRegistry serviceRegistry = ServiceRegistryFactory.createLocal();
+    serviceRegistry.init();
+    RegistryUtils.setServiceRegistry(serviceRegistry);
+    UnitTestMeta meta = new UnitTestMeta();
+    CseContext.getInstance()
+        .getSchemaListenerManager()
+        .setSchemaListenerList(Arrays.asList(new RestEngineSchemaListener()));
+
+    SchemaMeta schemaMeta = meta.getOrCreateSchemaMeta(CseAsyncClientHttpRequestTest.SpringmvcImpl.class);
+    CseContext.getInstance().getSchemaListenerManager().notifySchemaListener(schemaMeta);
+
+    Throwable error = new Error("failed");
+    Response response = Response.createConsumerFail(error);
+
+    CseAsyncClientHttpRequest client =
+        new CseAsyncClientHttpRequest(URI.create(
+            "cse://app:test/" + CseAsyncClientHttpRequestTest.SpringmvcImpl.class.getSimpleName() + "/bytes"),
+            HttpMethod.POST) {
+          @Override
+          protected CompletableFuture<ClientHttpResponse> doAsyncInvoke(Invocation invocation) {
+            CompletableFuture<ClientHttpResponse> completableFuture = new CompletableFuture<>();
+            completableFuture.complete(new CseClientHttpResponse(response));
+            return completableFuture;
+          }
+        };
+    ListenableFuture<ClientHttpResponse> future = client.executeAsync();
+    future.addCallback(
+        new ListenableFutureCallback<ClientHttpResponse>() {
+          @Override
+          public void onFailure(Throwable ex) {
+            Assert.assertSame(error, ex);
+          }
+
+          @Override
+          public void onSuccess(ClientHttpResponse result) {
+          }
+        }
+    );
+  }
+}
\ No newline at end of file
diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallbackTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallbackTest.java
new file mode 100644
index 000000000..5a41a4d91
--- /dev/null
+++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRequestCallbackTest.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.provider.springmvc.reference.async;
+
+import org.apache.servicecomb.provider.springmvc.reference.CseHttpEntity;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.http.HttpEntity;
+
+import mockit.Injectable;
+
+public class CseAsyncRequestCallbackTest {
+  @Test
+  public void testNormal() {
+    CseAsyncClientHttpRequest request = new CseAsyncClientHttpRequest();
+    @SuppressWarnings("unchecked")
+    CseAsyncRequestCallback cb = new CseAsyncRequestCallback(null);
+    cb.doWithRequest(request);
+    Assert.assertEquals(null, request.getContext());
+  }
+
+  @Test
+  @SuppressWarnings("unchecked")
+  public void testHttpEntity(@Injectable HttpEntity<?> entity) {
+    CseAsyncRequestCallback cb = new CseAsyncRequestCallback(entity);
+    CseAsyncClientHttpRequest request = new CseAsyncClientHttpRequest();
+    cb.doWithRequest(request);
+    Assert.assertEquals(entity.getBody(), request.getBody());
+  }
+
+  @Test
+  @SuppressWarnings("unchecked")
+  public void testCseEntity(@Injectable CseHttpEntity<?> entity) {
+    CseAsyncClientHttpRequest request = new CseAsyncClientHttpRequest();
+    entity.addContext("c1", "c2");
+    CseAsyncRequestCallback cb = new CseAsyncRequestCallback(entity);
+    cb.doWithRequest(request);
+    Assert.assertEquals(entity.getContext(), request.getContext());
+  }
+}
\ No newline at end of file
diff --git a/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplateTest.java b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplateTest.java
new file mode 100644
index 000000000..3e5ce64cb
--- /dev/null
+++ b/providers/provider-springmvc/src/test/java/org/apache/servicecomb/provider/springmvc/reference/async/CseAsyncRestTemplateTest.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.servicecomb.provider.springmvc.reference.async;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CseAsyncRestTemplateTest {
+
+  @Test
+  public void testCseAsyncRestTemplate() {
+    Assert.assertEquals(CseAsyncRestTemplate.class, new CseAsyncRestTemplate().getClass());
+  }
+}
\ No newline at end of file
diff --git a/samples/springmvc-sample/springmvc-consumer/src/main/java/org/apache/servicecomb/samples/springmvc/consumer/SpringmvcConsumerMain.java b/samples/springmvc-sample/springmvc-consumer/src/main/java/org/apache/servicecomb/samples/springmvc/consumer/SpringmvcConsumerMain.java
index 1571aa856..417cac64b 100644
--- a/samples/springmvc-sample/springmvc-consumer/src/main/java/org/apache/servicecomb/samples/springmvc/consumer/SpringmvcConsumerMain.java
+++ b/samples/springmvc-sample/springmvc-consumer/src/main/java/org/apache/servicecomb/samples/springmvc/consumer/SpringmvcConsumerMain.java
@@ -16,18 +16,28 @@
  */
 package org.apache.servicecomb.samples.springmvc.consumer;
 
+import java.lang.invoke.MethodHandles;
+
 import org.apache.servicecomb.foundation.common.utils.BeanUtils;
 import org.apache.servicecomb.foundation.common.utils.Log4jUtils;
 import org.apache.servicecomb.provider.pojo.RpcReference;
 import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
+import org.apache.servicecomb.provider.springmvc.reference.async.CseAsyncRestTemplate;
 import org.apache.servicecomb.samples.common.schema.Hello;
 import org.apache.servicecomb.samples.common.schema.models.Person;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Component;
+import org.springframework.util.concurrent.ListenableFuture;
+import org.springframework.util.concurrent.ListenableFutureCallback;
 import org.springframework.web.client.RestTemplate;
 
 @Component
 public class SpringmvcConsumerMain {
-
+  private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   private static RestTemplate restTemplate = RestTemplateBuilder.create();
 
   @RpcReference(microserviceName = "springmvc", schemaId = "springmvcHello")
@@ -50,6 +60,33 @@ public static void main(String[] args) throws Exception {
     // POJO Consumer
     System.out.println("POJO consumer sayhi services: " + hello.sayHi("Java Chassis"));
     System.out.println("POJO consumer sayhello services: " + hello.sayHello(person));
+
+    //AsyncRestTemplate Consumer
+    CseAsyncRestTemplate cseAsyncRestTemplate = new CseAsyncRestTemplate();
+    ListenableFuture<ResponseEntity<String>> responseEntityListenableFuture = cseAsyncRestTemplate
+        .postForEntity("cse://springmvc/springmvchello/sayhi?name=Java Chassis", null, String.class);
+    ResponseEntity<String> responseEntity = responseEntityListenableFuture.get();
+    System.out.println("AsyncRestTemplate Consumer sayHi services: " + responseEntity.getBody());
+
+    HttpEntity<Person> entity = new HttpEntity<>(person);
+    ListenableFuture<ResponseEntity<String>> listenableFuture = cseAsyncRestTemplate
+        .exchange("cse://springmvc/springmvchello/sayhello", HttpMethod.POST, entity, String.class);
+//    ResponseEntity<String> responseEntity1 = listenableFuture.get();
+//    System.out.println("AsyncRestTemplate Consumer sayHello services: " + responseEntity1.getBody());
+
+    listenableFuture.addCallback(
+        new ListenableFutureCallback<ResponseEntity<String>>() {
+          @Override
+          public void onFailure(Throwable ex) {
+            LOG.error("AsyncResTemplate Consumer catched exception when sayHello, ",ex);
+          }
+          @Override
+          public void onSuccess(ResponseEntity<String> result) {
+            System.out.println("AsyncRestTemplate Consumer sayHello services: " + result.getBody());
+          }
+        }
+    );
+
   }
 
   public static void init() throws Exception {


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

Mime
View raw message