1. 程式人生 > >RestTemplate原始碼解析及使用詳解

RestTemplate原始碼解析及使用詳解

一、RestTemplate服務呼叫

在前面Eureka的服務註冊與發現中,我們使用了一個非常有用的物件RestTemplate。該物件會使用Ribbon的自動化配置,同時通過配置@LoadBalanced還能開啟客戶端負載均衡。這裡我們詳細介紹RestTemplate針對不同請求型別和引數型別的服務呼叫實現。

什麼是RestTemplate?

RestTemplate是Spring提供的用於訪問Rest服務的客戶端,

RestTemplate提供了多種便捷訪問遠端Http服務的方法,能夠大大提高客戶端的編寫效率。

呼叫RestTemplate的預設建構函式,RestTemplate物件在底層通過使用java.net包下的實現建立HTTP 請求,

可以通過使用ClientHttpRequestFactory指定不同的HTTP請求方式。

ClientHttpRequestFactory介面主要提供了兩種實現方式

1、一種是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)建立底層的Http請求連線。

2、一種方式是使用HttpComponentsClientHttpRequestFactory方式,底層使用HttpClient訪問遠端的Http服務,使用HttpClient可以配置連線池和證書等資訊。

1、GET請求

在RestTemplate中,對GET請求可以通過如下兩個方法進行呼叫實現。

1.1、getForEntity函式。

該方法返回的是ResponseEntity,該物件是對HTTP請求響應的封裝,其中主要儲存了HTTP的幾個重要元素,
(url, requestMap,ResponseBean.class)這三個引數分別代表 REST請求地址、請求引數、HTTP響應轉換被轉換成的物件型別。

RestTemplate restTemplate = new RestTemplate();
//在url中使用佔位符並配合urlVariables引數實現GET請求的引數繫結。在第三個引數會替換url中{1}佔位符
ResponseEntity<String>  responseEntity = restTemplate.getForEntity("http://USER-SERVICE/user?name={1}",String.class,"tom");
String body = responseEntity.getBody();

若我們希望返回的body是一個User物件型別,也可以這樣實現:
 //http://USER-SERVICE/user?name=tom

 ResponseEntity<User> responseEntity = restTemplate.getForEntity("http://USER-SERVICE/user?name={1}", User.class, "tom");
 User body = responseEntity.getBody();

getForEntity函式還提供了以上三種不同的過載實現。

  • 1、getForEntity(String url, Class responseType, Object...urlVariables):

                    url:為請求的地址
                    responseType:為請求響應體body的包裝型別
                    urlVariables:為url中引數繫結
              

  • 2、getForEntity(String url, Class responseType, Map urlVariables):

 urlVariables使用的是Map型別,所以在使用該方法進行引數繫結時需要在佔位符中指定Map中引數的key值,比如url定義為http://USER-SERVICE/user?name={name}。在Map型別的urlVariables中,我們就需要put一個key值為name的引數來繫結url中的{name}佔位符的值,比如:

RestTemplate restTemplate = new RestTemplate();
Map<String,String> params = new HashMap<>();
params.put("name","data");
ResponseEntity<String> responseEntity = restTemplate.getForEneity("http://USER-SERVICE/user?name={name}",String.class,params);
  • 3、getForEntity(URI uri, Class responseType):

該方法使用url物件來替代之前的url和urlVariables引數來指定訪問地址和引數繫結。              

RestTemplate restTemplate = new RestTemplate();
UriComponents uriComponents = UriComponentsBuilder
    .fromUriString("http://USER-SERVICE/user?name={name}")
    .build()
    .expand("tom")
    .encode();
URI uri = uriComponents.toUri();
ResponseEntiy<String> responseEntity = restTemplate.getForEntity(uri,String.class);

1.2、getForObject函式

該方法可以理解為對getForEntity的進一步封裝。
它通過HttpMessageConverterExtractor對HTTP的請求響應體body內容進行物件轉換,實現請求直接返回包裝好的物件內容。

RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.getForObject(url,String.class);
//當body是一個User物件時:
User result = restTemplate.getForObject(url,User.class);

當不需要關注請求響應除body外的其他內容時,可以少一個從Response中獲取body的步驟。它與getForEntity函式類似,也提供了三種不同的過載實現。

  • 1、getForObject(String url, Class responseType, Object ...urlVariables):與getForEntity的方法類似.

                        url引數指定訪問的地址,
                        responseType引數定義該方法的返回型別,
                        urlVariables引數為url中佔位符定義的引數。

  • 2、getForObject(String url, Class responseType, Map urlVariables):

在該函式中,使用Map型別的urlVariable替代上面陣列形式的urlVariables,因此使用時在url中需要將佔位符的名稱與Map型別中的key一一對應配置。

  • 3、getForObject(URI uri, Class responseType):

該方法使用uri物件來替代之前的url和urlVariables引數使用。                

2、POST請求

在RestTemplate中,對POST請求時可以通過如下三種方式進行呼叫實現。

2.1、第一種postForEntity函式。

該方法同GET請求中getForEntity類似,會在呼叫後返回ResponseEntity<T>物件,其中T為請求響應的body型別。

如下使用postForEntity提交POST請求到USER-SERVICE服務的/user介面,提交的body內容為user物件,請求響應返回的body型別為String型別。

ResponseTemplate responseTemplate = new RestTemplate();
User user = new User("tom",30);
ResponseEntity<String> responseEntity = responseTemplate.postForEntity("http://USER-SERVICE/user", user, String.class);
String body = responseEntity.getBody();

 postForEntity也實現了三種不同的過載的方法。

  • postForEntity(String url, Object request, Class responseTemplate, Object ...urlVariables);
  • postForEntity(String url, Object request, Class responseTemplate, Map urlVariables);
  • postForEntity(URI url, Object request, Class responseType);

其中第一個過載函式和第二個過載函式中的urlVariables引數都用來對url中的引數進行繫結使用;responseType引數是對請求響應的body內容的型別定義。這裡需要注意的是新增加的request引數,該物件可以是一個普通物件,也可以是一個HttpEntity物件。

如果是一個普通物件,而非HttpEntity物件的時候,RestTemplate會將請求物件轉換為一個HttpEntity物件來處理,其中Object就是request的型別, request內容會被視作完整的body來處理; 而如果request是一個HttpEntity物件,那麼就會被當做一個完整的HTTP請求物件來處理,這個request中不僅包含了body內容, 也包含了header的內容。                

2.2、第二種postForObject函式

該方法也跟getForObject的型別類似,他的作用是簡化postForEntity的後續處理。通過直接將請求響應的body內容包裝成物件來返回使用,比如下面的例子:

RestTemplate restTemplate = new RestTemplate();
User user = new User("tom",20);
String postResult = restTemplate.postForObject("http://USER-SERVICE/user/", user, String.class);

 postForObject函式也實現了三種不同的過載方法:

  • postForObject(String url, Object request, Class responseType, Object... urlVariables);
  • postForObject(String url, Object request, Class responseType, Map urlVariables);
  • postForObject(URI uri, Object request, Class responseType);

這三種函式除了返回物件型別不同,函式的傳入引數均與postForEntity一致。                    

2.3、 第三種:postForLocation函式。

該方法實現了以post請求提交資源,並返回新的資源URI,比如下面的例子:              

User user = new User("tom", 40);
URI responseURI = restTemplate.postForLocation("http://USER-SERVICE/user/",user);

postForLocation函式也實現了三種不同的過載方式:

  • postForLocation(String url, Object request, Object... urlVariables);
  • postForLocation(String url, Object request, Map urlVariables);
  • postForLocation(URI uri, Object request);

由於postForLocation函式會返回新的資源URI,該URI相當於指定了返回型別,所有此方法實現的POST請求不需要postForEntity和postForObject那樣指定responseType。其他的引數用法相同。

3、PUT請求

在RestTemplate中,對PUT請求可以通過put方法進行呼叫實現,比如:   

RestTemplate restTemplate = new RestTemplate();
Long id = 10001L;
User user = new User("tom", 20);
restTemplate.put("http://USER-SERVICE/user/{1}",user,id);

post函式也實現了三種不同的過載方法:

  • put(String url, Object request, Object... urlVariables);
  • put(String url, Object request, Map urlVariables);
  • put(URI uri, Object request);

 put函式為void型別,所以沒有返回內容,也就沒有其他函式定義的responseType引數,除此之外的其他傳入引數定義與用法與postForObject一致。               

4、DELETE請求

在RestTemplate中,對DELETE請求可以通過delete方法進行呼叫實現,比如:       

RestTemplate restTemplate = new RestTemplate();
long id = 10001L;
restTemplate.delete("http://USER-SERVICE/user/{1}",id);

delete函式也實現了三種不同的過載方法:

  • delete(String url, Object... urlVariables);
  • delete(String url, Map urlVariables);
  • delete(URI url);            

二、原始碼解析

RestTemplate 解析:

https://blog.csdn.net/wangqiubo2010/article/details/81708643

【Spring-web】RestTemplate原始碼學習:

https://www.cnblogs.com/quiet-snowy-day/p/6210288.html