1. 程式人生 > 實用技巧 >服務消費

服務消費

當我們實現了服務註冊的時候,也同步獲取到了註冊成功的服務資訊,就可以直接呼叫服務,我們今天來實踐下。

一、準備工作

1.1 建立 Eureka- Server

  1. 新建 Eureka Server 模組,新增 Eureka Server 依賴
<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Hoxton.SR4</spring-cloud.version>
</properties>
    
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
    
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>		
</dependencies>		    
  1. 在配置檔案 resources/application. yml 中新增 EurekaServer 相關配置
# 指定執行埠
server:
  port: 9000      
spring:
  application:
	# 指定服務名稱
    name: eureka-server
eureka:
  instance:
    # 指定主機地址
    hostname: localhost
  client:
    # 指定是否從註冊中心獲取服務(註冊中心不需要開啟)
    fetch-registry: false
    # 指定是否將自身註冊到註冊中心(註冊中心不需要開啟)
    register-with-eureka: false
  1. 在啟動類上新增 @EnableEurekaServer 註解來啟用 Euerka 註冊中心功能
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }

}
  1. 啟動專案,訪問 http://localhost:9000 ,可以看到 Eureka 註冊中心介面:

1.2 建立 PriceService 模組

  1. 新增依賴
<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Hoxton.SR4</spring-cloud.version>
</properties>
    
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
    
<dependencies>
    <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.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>	
  1. 在配置檔案 resources/application. yml 新增相關配置
spring:
  application:
    # 指定服務名稱
    name: price-service

eureka:
  client:
    # 註冊到 Eureka 的註冊中心
    register-with-eureka: true
    # 獲取註冊例項列表
    fetch-registry: true
    service-url:
      # 指定註冊中心
      defaultZone: http://localhost:9000/eureka
  1. 在啟動類上新增 @EnableDiscoveryClient 註解
@EnableDiscoveryClient
@SpringBootApplication
public class PriceServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(PriceServiceApplication.class, args);
    }

}
  1. 建立 PriceController,實現根據商品Id 獲取價格功能
@RestController
@RequestMapping("/price")
public class PriceController {

    @GetMapping("/getPrice/{productId}")
    public BigDecimal getPrice(@PathVariable("productId") String productId) {
        System.out.println("productId=" + productId);
        return new BigDecimal("100");
    }

}
  1. 啟動兩個 PriceService 服務

1.3 建立 OrderService 模組

  1. 新增依賴
<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Hoxton.SR4</spring-cloud.version>
</properties>
    
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
    
<dependencies>
    <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.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>	
  1. 在配置檔案 resources/application. yml 新增相關配置
server:
  # 指定執行埠
  port: 8005
spring:
  application:
    # 指定服務名稱
    name: order-service

eureka:
  client:
    # 註冊到 Eureka 的註冊中心
    register-with-eureka: true
    # 獲取註冊例項列表
    fetch-registry: true
    service-url:
      # 指定註冊中心
      defaultZone: http://localhost:9000/eureka

  1. 在啟動類上新增 @EnableDiscoveryClient 註解
@EnableDiscoveryClient
@SpringBootApplication
public class OrderServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }

}

  1. 新建 OrderController 用於訪問 PriceService 獲取價格
@RestController
@RequestMapping("/order")
public class OrderController {

    private final RestTemplate restTemplate;

    public OrderController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @GetMapping("/getPrice")
    public BigDecimal getPrice(String productId) {
        // TODO 方法待實現
		return null;
    }

}

二、負載均衡

當一個服務存在多個例項的,我們就需要使用能夠滿足負載均衡的 HTTP 元件。

2.1 Loadbalancer

2.1.1 Loadbalancer 介紹

LoadBalancerClientSpringCloud 提供的負載均衡器客戶端,它先從提供的服務中獲取某一個例項(預設策略為輪詢),通過 choose() 方法獲取到節點中的一個服務,拿到服務的資訊之後取出服務 IP 資訊,就可以得到完成的想要訪問的 IP地址和介面,最後通過 RestTempate 訪問服務。

2.1.2 Loadbalancer 使用

  1. 新建 HttpConfig ,啟用 @LoadBalanced 實現負載均衡功能
@Configuration
public class HttpConfig {

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  1. 完善 OrderController.getPrice() 方法
@GetMapping("/getPrice")
public BigDecimal getPrice(String productId) {
    final BigDecimal price = restTemplate.getForObject("http://PRICE-SERVICE/price/getPrice/" + productId, BigDecimal.class);
    return price;
}
  1. 啟動 OrderService 服務,訪問 http://localhost:8005/order/getPrice?productId=123 ,返回:
100

說明呼叫成功了,我們再訪問二次請求,然後檢視 PriceService 控制檯輸出:

檢視 PriceService01控制檯:

productId=123
productId=123

檢視 PriceService02 控制檯:

productId=123

可以看到使用了輪詢機制。

2.2 Ribbon

Spring Cloud Netflix RibbonSpring Cloud Netflix 子專案的核心元件之一,主要給服務間呼叫及 API 閘道器轉發提供負載均衡的功能。

2.2.1 Ribbon的常用配置

全域性配置:

ribbon:
  ConnectTimeout: 1000 #服務請求連線超時時間(毫秒)
  ReadTimeout: 3000 #服務請求處理超時時間(毫秒)
  OkToRetryOnAllOperations: true #對超時請求啟用重試機制
  MaxAutoRetriesNextServer: 1 #切換重試例項的最大個數
  MaxAutoRetries: 1 # 切換例項後重試最大次數
  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改負載均衡演算法

指定服務進行配置:

user-service:
  ribbon:
    ConnectTimeout: 1000 #服務請求連線超時時間(毫秒)
    ReadTimeout: 3000 #服務請求處理超時時間(毫秒)
    OkToRetryOnAllOperations: true #對超時請求啟用重試機制
    MaxAutoRetriesNextServer: 1 #切換重試例項的最大個數
    MaxAutoRetries: 1 # 切換例項後重試最大次數
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #修改負載均衡演算法

可以看出與全域性配置的區別就是 ribbon 節點掛在服務名稱下面。

2.2.2 Ribbon的負載均衡策略

ribbon可以選擇以下幾種負載均衡策略:

* com.netflix.loadbalancer.RandomRule:從提供服務的例項中以隨機的方式;
* com.netflix.loadbalancer.RoundRobinRule:以線性輪詢的方式,就是維護一個計數器,從提供服務的例項中按順序選取,第一次選第一個,第二次選第二個,以此類推,到最後一個以後再從頭來過;
* com.netflix.loadbalancer.RetryRule:在RoundRobinRule的基礎上新增重試機制,即在指定的重試時間內,反覆使用線性輪詢策略來選擇可用例項;
* com.netflix.loadbalancer.WeightedResponseTimeRule:對RoundRobinRule的擴充套件,響應速度越快的例項選擇權重越大,越容易被選擇;
* com.netflix.loadbalancer.BestAvailableRule:選擇併發較小的例項;
* com.netflix.loadbalancer.AvailabilityFilteringRule:先過濾掉故障例項,再選擇併發較小的例項;
* com.netflix.loadbalancer.ZoneAwareLoadBalancer:採用雙重過濾,同時過濾不是同一區域的例項和故障例項,選擇併發較小的例項。

三、Feign

3.1 Feign 介紹

Feign 是一個宣告式的Web Service客戶端,它使得編寫 Web Serivce 客戶端變得更加簡單。我們只需要使用Feign 來建立一個介面並用註解來配置它既可完成。它具備可插拔的註解支援,包括 Feign註解和 JAX-RS 註解。Feign 也支援可插拔的編碼器和解碼器。Spring CloudFeign 增加了對 Spring MVC 註解的支援,還整合了RibbonEureka 來提供負載均衡的HTTP客戶端實現。

3.2 FeignClient註解屬性

屬性名 預設值 作用 備註
value 空字串 呼叫服務名稱,和name屬性相同
serviceId 空字串 服務id,作用和name屬性相同 已過期
name 空字串 呼叫服務名稱,和value屬性相同
url 空字串 全路徑地址或hostname,http或https可選
decode404 false 配置響應狀態碼為404時是否應該丟擲FeignExceptions
configuration {} 自定義當前feign client的一些配置 參考FeignClientsConfiguration
fallback void.class 熔斷機制,呼叫失敗時,走的一些回退方法,可以用來丟擲異常或給出預設返回資料。 底層依賴hystrix,啟動類要加上@EnableHystrix
path 空字串 自動給所有方法的requestMapping前加上字首,類似與controller類上的requestMapping
primary true

3.3 Feign 簡單使用

  1. OrderService 模組中新增 Feign 依賴
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  1. 啟用 Feign 註解
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class OrderServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }

}
  1. 建立 PriceService 介面
@FeignClient(value = "PRICE-SERVICE", path = "/price")
public interface PriceService {

    @RequestMapping(value = "/getPrice/{productId}", method = RequestMethod.GET)
    BigDecimal getPrice(@PathVariable("productId")String productId);

}

可以看到相當於是一個和 PriceService 訪問的契約。

  1. 修改 OrderController 呼叫邏輯
@RestController
@RequestMapping("/order")
public class OrderController {

    private final PriceService priceService;

    public OrderController(PriceService priceService) {
        this.priceService = priceService;
    }

    @GetMapping("/getPrice")
    public BigDecimal getPrice(String productId) {
        final BigDecimal price = priceService.getPrice(productId);
        return price;
    }

}

5)執行 OrderService 服務,訪問 http://localhost:8005/order/getPrice?productId=123 ,返回:

100

說明呼叫成功。