在第3章講解Eureka時,我們提到了Eureka會保存各個服務的元數據,元數據中包含了各個服務的地址等信息。那么服務之間到底是怎樣通過這些信息進行交互的呢?
Spring Cloud服務間的調用默認支持兩種方式:Ribbon和Feign,具體來說就是使用RestTemplate和FeignClient來調用。不管使用什么方式,本質上都是通過REST接口調用服務的HTTP接口,參數和結果默認都是通過jackson序列化和反序列化的。
前面我們已經創建了customer微服務,這里我們再新建一個order微服務。使用兩個服務來進行服務間調用的學習。
order微服務的端口號設置為8002。order微服務的pom.xml引入了如下包:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
其中spring-cloud-starter-netflix-ribbon 引入了Ribbon支持。
為了使用Ribbon訪問customer服務的接口,我們在order的啟動類中加入了如下代碼,加載RestTemplate。
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
注意:這里使用的注解@Loadbalanced是用來開啟Ribbon負載均衡的。如果沒有添加此注解,那么得到的restTemplate就不具備Ribbon的負載均衡功能,也不會識別微服務的實例名,只能當作傳統的http訪問工具類來使用。
編寫測試controller。
@RestController
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/users/{userId}")
public String getUserInfo(@PathVariable Long userId) {
System.out.printf("這里要使用Ribbon來遠程調用customer服務獲取用戶信息");
String userInfoStr = restTemplate.getForObject("http://customer/users/" +
userId, String.class);
return userInfoStr;
}
}
通過這樣,就可以訪問customer服務中的接口,customer中的接口代碼如下:
@GetMapping("/users/{userId}")
public String getUserInfoByUserId(@PathVariable Long userId){
return "userInfo with userId = " + userId;
}
在瀏覽器中訪問http://localhost:8002/users/1001,可以得到如5.1的結果。

通過上面的例子,我們通過RestTemplate在order和customer之間進行了服務間的http請求,內部請求過程中使用了http://customer/users/這個地址,並沒有涉及到域名端口之類的東西。這里的customer就是我們之前提到的實例名。也就是這個服務在整個系統中的唯一名稱。
5.1 Ribbon
Ribbon是Netflix發布的負載均衡器,它有助於控制HTTP和TCP的客戶端的行為。為Ribbon配置服務提供者地址后,Ribbon就可基於某種負載均衡算法,自動地幫助服務消費者去請求。Ribbon默認為我們提供了很多負載均衡算法,例如輪詢、隨機等。當然,我們也可為Ribbon實現自定義的負載均衡算法。
在Spring Cloud中,Ribbon可自動從Eureka Server獲取服務提供者地址列表,並基於負載均衡算法,請求其中一個服務提供者實例。在本章剛開始,我們新建的order服務使用RestTemplate調用customer接口的實例就是使用了帶有Ribbon功能的RestTemplate。
RestTemplate提供了若干方便我們使用的工具方法,通過這些方法可以很方便地實現網絡訪問/服務間調用。
接下來我們介紹幾個常見的方法。
- delete():在特定的URL上對資源執行HTTP DELETE操作。
-
getForEntity():發送一個HTTP
GET請求,返回的ResponseEntity包含了響應體所映射成的對象。
- getForObject():發送一個HTTP GET請求,返回的請求體將映射為一個自定義對象。
-
postForEntity():POST
數據到一個URL,返回包含一個對象的ResponseEntity,這個對象是從響應體中映射得到的。
- postForObject():POST 數據到一個URL,返回根據響應體匹配形成的對象。
- headForHeaders():發送HTTP HEAD請求,返回包含特定資源URL的HTTP頭。
- optionsForAllow():發送HTTP OPTIONS請求,返回對特定URL的Allow頭信息。
- postForLocation():POST 數據到一個URL,返回新創建資源的URL。
- put():PUT 資源到特定的URL。
- execute():在URL上執行特定的HTTP方法,返回一個從響應體映射得到的對象。
- exchange():在URL上執行特定的HTTP方法,返回包含對象的ResponseEntity,這個對象是從響應體中。
5.2 Feign
Feign 是一個聲明web服務客戶端,它使編寫web服務客戶端更容易,使用Feign
創建一個接口並對它進行注解,它具有可插拔的注解支持包括Feign注解與JAX-RS注解,Feign還支持可插拔的編碼器與解碼器,Spring
Cloud 增加了對 Spring MVC的注解,Spring Web 默認使用了HttpMessageConverters,
Spring Cloud 集成 Ribbon 和 Eureka 提供的負載均衡的HTTP客戶端 Feign。
為order服務添加feign支持。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-feign</artifactId>
</dependency>
為啟動類添加注解@EnableFeignClients,開啟Feign掃描。
新建service接口類,代碼如下:
@FeignClient("customer")
public interface UserService {
@GetMapping("/users/{userId}")
String getUserInfoByUserId(@PathVariable Long userId);
}
在UserController中添加接口方法。
@GetMapping("/feign/users/{userId}")
public String getUserInfoWithFeign(@PathVariable Long userId){
System.out.printf("這里要使用Feign來遠程調用customer服務獲取用戶信息");
String userInfoStr = userService.getUserInfoByUserId(userId);
return userInfoStr;
}
啟動order服務,瀏覽器訪問http://localhost:8002/feign/users/100112。得到如圖5.2的結果。

5.3 小結
本章主要了解了如何使用Ribbon和Feign通過Eureka的實例來進行服務間的接口調用。到本文為止,我們已經可以構建一些簡單的微服務,並可以讓它們注冊到同一個注冊中心,連接到同一個配置中心,並且可以在不需要url的情況下進行服務間交互。