(四)springcloud 生產消費-Spring Cloud OpenFeign


相對概念,生產者:被調用方;消費者:調用方

服務生產:

依賴:

<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-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

配置:

server:
  port: 2000
spring:
  application:
    name: provider-server
  profiles:
    active: dev
  cloud:
    config:
      label: master
      profile: ${spring.profiles.active}
      discovery:
        service-id: config-server
        enabled: true
        
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka/

啟動類:

/**
 * 不用再聲明開啟注冊中心,自動配置了
 */
@SpringBootApplication
public class ProviderApplication {

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

服務:

@RestController
@RequestMapping("/api/v1/provider")
public class ProviderController {

    @Value("${server.port}")
    private String port;

    @GetMapping("/port")
    public String port() {
        return port;
    }
  
}

服務消費(Ribbon):

依賴:

<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-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

配置:

server:
  port: 3000
spring:
  application:
    name: consumer-server-ribbon
  profiles:
    active: dev
  cloud:
    config:
      label: master
      profile: ${spring.profiles.active}
      discovery:
        service-id: config-server
        enabled: true

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka/

啟動類:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

@SpringBootApplication
public class ConsumerRibbonApplication {

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

  	// 加載Ribbon,應用負載均衡
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @RestController
    @RequestMapping("/api/v1/consumer")
    class ProviderController {

        private static final String SERVICE_NAME = "provider-server";
      
        private static final String GET_PORT = "/api/v1/provider/port";

        @Resource
        private RestTemplate restTemplate;

        @GetMapping
        public String consumer() {
          	// 調用生產者服務
            ResponseEntity<String> forEntity = restTemplate
              .getForEntity("http://" + SERVICE_NAME + GET_PORT, String.class, (Object) null);
            return forEntity.getBody();
        }
    }

}

驗證:

訪問消費者:http://localhost:3000/api/v1/consumer

獲得響應:2000

Ribbon主要包含如下組件:

IRule:

根據特定算法中從服務列表中選取一個要訪問的服務

  • RoundRobinRule:輪詢規則,默認規則。同時也是更高級rules的回退策略
  • AvailabilityFilteringRule:優先過濾掉由於多次訪問故障而處於斷路器跳閘狀態,並發的連接數量超過閾值
  • WeightedResponseTimeRule:根據平均響應時間計算所有服務的權重,響應時間越快,服務權重越重、被選中的概率越高
  • RetryRule:先按照RoundRobinRule的策略獲取服務,如果獲取服務失敗,則在指定時間內會進行重試,獲取可用的服務
  • BestAvailableRule:此負載均衡器會先過濾掉由於多次訪問故障而處於斷路器跳閘狀態的服務,然后選擇一個並發量最小的服務
  • RandomRule:隨機獲取一個服務

IPing:

在后台運行的一個組件,用於檢查服務列表是否都可用

  • NIWSDiscoveryPing:不執行真正的ping。如果Discovery Client認為是在線,則程序認為本次心跳成功,服務可用
  • PingUrl:此組件會使用HttpClient調用服務的一個URL,如果調用成功,則認為本次心跳成功,表示此服務活着
  • NoOpPing:永遠返回true, 即認為服務永遠活着
  • DummyPing:默認實現,默認返回true,即認為服務永遠活着

ServerList:

存儲服務列表。分為靜態和動態。如果是動態的,后台有個線程會定時刷新和過濾服務列表

  • ConfigurationBasedServerList:從配置文件中獲取所有服務列表
sample-client.ribbon.listOfServers=www.microsoft.com:80,www.yahoo.com:80,www.google.com:80
  • DiscoveryEnabledNIWSServerList:從服務注冊表中獲取服務列表。此值必須通過屬性中的VipAddress來標識服務器集群。DynamicServerListLoadBalancer會調用此對象動態獲取服務列表
  • DomainExtractingServerList:代理類,根據ServerList的值實現具體的邏輯

ServerListFilter:

該接口允許過濾配置或動態獲取的具有所需特性的服務器列表。ServerListFilter是DynamicServerListLoadBalancer用於過濾從ServerList實現返回的服務器的組件。

  • ZoneAffinityServerListFilter:過濾掉所有的不和客戶端在相同zone的服務,如果和客戶端相同的zone不存在,才不過濾不同zone有服務。
<clientName>.ribbon.EnableZoneAffinity=true
  • ZonePreferenceServerListFilter:是比較的zone是發布環境里面的zone。過濾掉所有和客戶端環境里的配置的zone的不同的服務,如果和客戶端相同的zone不存在,才不進行過濾。
  • ServerListSubsetFilter:此過濾器確保客戶端僅看到由ServerList實現返回的整個服務器的固定子集。 它還可以定期用新服務器替代可用性差的子集中的服務器

其他配置:

consumer-server-ribbon:
  ribbon:
  	# 請求連接的超時時間
    ConnectTimeout: 250 
    # 請求處理的超時時間
    ReadTimeout: 1000
    # 對所有操作請求都進行重試
    OkToRetryOnAllOperations: true  
    # 切換實例的重試次數
    MaxAutoRetriesNextServer: 2 
    # 對當前實例的重試次數
    MaxAutoRetries: 1 
		# 定義負載均衡規則
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

服務消費(Feign):

依賴:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-openfeign</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-config</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

配置:

server:
  port: 3001
spring:
  application:
    name: consumer-server-feign
  profiles:
    active: dev
  cloud:
    config:
      label: master
      profile: ${spring.profiles.active}
      discovery:
        service-id: config-server
        enabled: true

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8761/eureka/

聲明調用生產者的接口:

@FeignClient(name = "provider-server")
@RequestMapping("/api/v1/provider")
public interface ProviderClient {

    @GetMapping("/port")
    String port();

}

啟動類:

@EnableFeignClients:開啟Feign功能

@SpringBootApplication
@EnableFeignClients
public class ConsumerFeignApplication {

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

    @RestController
    @RequestMapping("/api/v1/consumer")
    public class OrderController {

        @Resource
        private ProviderClient providerClient;

        @GetMapping
        public String productInfo() {
            return providerClient.port();
        }
    }

}
# feign 配置
feign:
  hystrix:
    enabled: true
  okhttp:
    enabled: true
  httpclient:
    enabled: false
  client:
    config:
      default:
        connectTimeout: 10000
        readTimeout: 10000
  # 請求和響應GZIP壓縮支持
  compression:
    request:
      enabled: true
    response:
      enabled: true

驗證:

訪問消費者:http://localhost:3000/api/v1/consumer

獲得響應:2000

配置:

1、請求響應壓縮配置

feign.compression.request.enabled=true
feign.compression.response.enabled=true
# 設置支持的 mime-types
feign.compression.request.mime-types=text/xml,application/xml,application/json
# 選擇壓縮介質類型和最小請求閾值長度。
feign.compression.request.min-request-size=2048

feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
	compression:
		request: 
			enabled: true
			mime-types: text/xml,application/xml,application/json
			min-request-size: 2048
		response:
			enabled: true

日志:

記錄器的名稱是用於創建Feign客戶端的接口的完整類名。Feign日志記錄僅響應DEBUG級別。

logging: 
	level:
		project.user.UserClient: DEBUG

Logger.Level配置:

  • NONE,沒有記錄(DEFAULT)。
  • BASIC,僅記錄請求方法和URL以及響應狀態代碼和執行時間。
  • HEADERS,記錄基本信息以及請求和響應標頭。
  • FULL,記錄請求和響應的標題,正文和元數據。
@Configuration
public class FooConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

@QueryMap:

OpenFeign @QueryMap注釋為POJO提供了對用作GET參數映射的支持。不幸的是,默認的OpenFeign QueryMap注釋與Spring不兼容,因為它缺少value屬性。

Spring Cloud OpenFeign提供等效@SpringQueryMap注釋,用於將POJO或Map參數注釋為查詢參數映射。

@FeignClient("demo")
public class DemoClient {

    @GetMapping(path = "/demo")
    String demoEndpoint(@SpringQueryMap Params params);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM