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