1. 程式人生 > 實用技巧 >【SpringCloud】07.應用間的通訊

【SpringCloud】07.應用間的通訊

應用間通訊

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;
    }
  1. 先增加@Autowired LoadBalancerClient
  2. 通過loadBalancerClient.choose("ServerId");返回一個ServiceInstance
  3. serviceInstance.getHost()serviceInstance.getPort()可以分別獲得主機以及埠號
  4. 拼接主機以及埠
  5. 通過第一種方法的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有三種方式:

  1. url寫死,用new RestTemplate () 訪問url來獲取訊息
  2. 使用loadBalancerClient獲取到url,然後使用new RestTemplate () 訪問url 獲取資訊
  3. 利用@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;
    }
}