【SpringCloud】07.應用間的通訊
阿新 • • 發佈:2020-08-19
應用間通訊
HTTP vs RPC
- Spring Cloud (HTTP)
- Dubbo (RPC)
1.SpringCloud中服務間兩種restful呼叫方式
- RestTemplate
- Feign
方式一、RestTemplate:是一個http客戶端
RestTemplate有三種方式
1.直接寫url :http://localhost:8080/msg
使用restTemplate.getForObject("http://localhost:8080/msg", String.class);方法
@RestController @Slf4j public class ClientController { @GetMapping("/getProductMsg") public String getProductMsg(){ //1. 第一種方式 RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject("http://localhost:8080/msg", String.class); log.info("response={}",response); return response; } }
缺點:地址是寫死的,如果對方服務有多臺,這樣很不好。
2.通過 ServiceInstance serviceInstance = loadBalancerClient.choose("ServerId"); 獲得服務的資訊。
ServerId :服務的名字
@Autowired
private LoadBalancerClient loadBalancerClient;
@RestController @Slf4j public class ClientController { @Autowired private LoadBalancerClient loadBalancerClient; @GetMapping("/getProductMsg") public String getProductMsg(){ //2.第二種 ServiceInstance serviceInstance= loadBalancerClient.choose("PRODUCT"); String url = String.format("http://%s:%s",serviceInstance.getHost(),serviceInstance.getPort())+"/msg"; RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject(url, String.class); log.info("response={}",response); return response; }
- 先增加@Autowired LoadBalancerClient
- 通過loadBalancerClient.choose("ServerId");返回一個ServiceInstance
- serviceInstance.getHost()、serviceInstance.getPort()可以分別獲得主機以及埠號
- 拼接主機以及埠
- 通過第一種方法的restTemplate.getForObject(url, String.class)請求資料
方法 | 說明 | 返回例子 |
---|---|---|
serviceInstance.getUri() | 路徑 | http://localhost:8080 |
serviceInstance.getHost() | 主機 | localhost |
serviceInstance.getServiceId() | 服務id | PRODUCT |
serviceInstance.getPort() | 埠號 | 8080 |
優點:我們可以不知道服務的路徑,通過服務Id或者服務路徑資訊
缺點:編碼比較繁瑣
3.用@LoadBalanced 可在restTemplate裡使用應用名字來訪問
@Component
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
@RestController
@Slf4j
public class ClientController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/getProductMsg")
public String getProductMsg(){
//3.第三種方式 利用@LoadBalanced 可在restTemplate裡使用應用名字
String response = restTemplate.getForObject("http://PRODUCT/msg", String.class);
log.info("response={}",response);
return response;
}
}
總結
RestTemplate有三種方式:
- url寫死,用new RestTemplate () 訪問url來獲取訊息
- 使用loadBalancerClient獲取到url,然後使用new RestTemplate () 訪問url 獲取資訊
- 利用@LoadBalanced註解restTemplate,然後restTemplate就可以使用應用名稱來訪問(通過ribbon依據某種規則,如簡單輪詢、隨機連線去連線目標服務來實現負載均衡)
方式二、Feign
- 本質還是http客戶端
- 宣告式REST客戶端(偽RPC)
- 才用了基於介面的註解
- 內部也使用Ribbon做負載均衡
通過feign我們能把http遠端呼叫對開發者完全透明,得到與呼叫本地方法一樣的編碼體驗
使用方法:
1.在pom中增加Feign依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>2.0.0.M1</version>
</dependency>
2.在啟動類增加註解@EnableFeignClients 開啟Feign功能 (org.springframework.cloud.netflix.feign.EnableFeignClients;)
package com.imooc.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
3.在客戶端定義好要呼叫的服務和介面
- 介面使用@FeignClient(name="需要呼叫的應用名稱")
- 方法的註解是需要呼叫介面的地址(也可以使用@RequestMapping、@PostMapping)
如我們想呼叫的介面地址為“/order/addOrder”,且為GET請求, 那就寫@GetMapping("/order/addOrder")
package com.imooc.order.client;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name="product")
public interface ProductClient {
@GetMapping("/msg")
String productMsg();
}
4.客戶端依賴注入③定義好的介面,然後直接呼叫即可。
package com.imooc.order.controller;
import com.imooc.order.client.ProductClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@Slf4j
public class ClientController {
@Autowired
private ProductClient productClient;
@GetMapping("/getProductMsg")
public String getProductMsg(){
String response = productClient.productMsg();
log.info("response={}",response);
return response;
}
}