SpringCloud-Feign SpringCloud Feign

SpringCloud Feign

Feign介紹

Feign是一個聲明式的Web Service客戶端,它使得編寫Web Serivce客戶端變得更加簡單。我們只需要使用Feign來創建一個接口並用註解來配置它既可完成。
它具備可插拔的註解支持,包括Feign註解和JAX-RS註解。Feign也支持可插拔的編碼器和×××。Spring Cloud爲Feign增加了對Spring MVC註解的支持,
還整合了Ribbon和Eureka來提供均衡負載的HTTP客戶端實現。

Feign原理簡述

  • 啓動時,程序會進行包掃描,掃描所有包下所有@FeignClient註解的類,並將這些類注入到spring的IOC容器中。
  • 當定義的Feign中的接口被調用時,通過JDK的動態代理來生成RequestTemplate。
  • RequestTemplate中包含請求的所有信息,如請求參數,請求URL等。
  • RequestTemplate聲場Request,然後將Request交給client處理,這個client默認是JDK的HTTPUrlConnection,也可以是OKhttp、Apache的HTTPClient等。
    最後client封裝成LoadBaLanceClient,結合ribbon負載均衡地發起調用。

Feign遠程調用的基本流程


1.Feign核心:將以java註解的方式定義的遠程調用API接口,最終轉換成HTTP的請求形式,然後將HTTP的請求的響應結果,解碼成JAVA Bean,放回給調用者。
2.Feign通過處理註解,將請求模板化,當實際調用的時候,傳入參數,
根據參數再應用到請求上,進而轉化成真正的 Request 請求。

Feign遠程調用的重要組件

在微服務啓動時,Feign會進行包掃描,對加@FeignClient註解的接口,
按照註解的規則,創建遠程接口的本地JDK Proxy代理實例。然後,
將這些本地Proxy代理實例,注入到Spring IOC容器中。當遠程接口的方法被調用,由Proxy代理實例去完成真正的遠程訪問,並且返回結果。

關鍵註解

  • @EnableFeignClients
  • @FeignClient

@EnableFeignClients

該註解作用於啓動類

@FeignClient

  1. FeignClient註解被@Target(ElementType.TYPE)修飾,表示FeignClient註解的作用目標在接口上
  2. @FeignClient標籤的常用屬性如下
  • name:指定FeignClient的名稱,如果項目使用了Ribbon,name屬性會作爲微服務的名稱,用於服務發現
  • url: url一般用於調試,可以手動指定@FeignClient調用的地址
  • decode404:當發生http 404錯誤時,如果該字段位true,會調用decoder進行解碼,否則拋出FeignException
  • configuration: Feign配置類,可以自定義Feign的Encoder、Decoder、LogLevel、Contract
  • fallback: 定義容錯的處理類,當調用遠程接口失敗或超時時,會調用對應接口的容錯邏輯,fallback指定的類必須實現@FeignClient標記的接口
  • fallbackFactory: 工廠類,用於生成fallback類示例,通過這個屬性我們可以實現每個接口通用的容錯邏輯,減少重複的代碼
  • path: 定義當前FeignClient的統一前綴

環境準備

開發環境

  • JDK:1.8
  • SpringBoot:2.1.16.RELEASE
  • SpringCloud:Finchley

項目結構

  • halo-cloud-parent 父工程
  • halo-cloud-provider 服務提供者
  • halo-cloud-feign 服務消費者
  • halo-cloud-server 註冊中心

Feign使用

halo-cloud-parent

  • pom.xml
 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <version>2.1.16.RELEASE</version>
         <relativePath/> <!-- lookup parent from repository -->
     </parent>
     <groupId>com.cloud</groupId>
     <artifactId>parent</artifactId>
     <version>0.0.1-SNAPSHOT</version>
     <name>parent</name>
     <description>父工程</description>
     <properties>
         <java.version>1.8</java.version>
     </properties>

     <!--打包方式-->
     <packaging>pom</packaging>
     <modules>
         <module>halo-cloud-server</module>
         <module>halo-cloud-feign</module>
         <module>halo-cloud-provider</module>
     </modules>
 
     <dependencies>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter</artifactId>
         </dependency>
 
         <!--web依賴-->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-commons</artifactId>
         </dependency>
 
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
 
 
     <dependencyManagement>
         <!--引入springcloud依賴的-->
         <dependencies>
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-dependencies</artifactId>
                 <version>Greenwich.RELEASE</version>
                 <type>pom</type>
                 <scope>import</scope>
             </dependency>
         </dependencies>
     </dependencyManagement>
 </project>

halo-cloud-server

  • pom.xml
  <!--eureka server 依賴座標-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
  • application.yml
server:  # 服務端口
  port: 9090
spring:
  application:  # 應用名字,eureka 會根據它作爲服務id
    name: halo-cloud-server

#  eureka配置
eureka:
  instance:
    hostname: localhost
  client:
    service-url:   #  eureka server 的地址, 咱們單實例模式就寫自己好了
      defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka
    register-with-eureka: false # 不向eureka server 註冊自己
    fetch-registry: false # 不向eureka server 獲取服務列表
  • ServerApplication.java
@EnableEurekaServer
@SpringBootApplication
public class ServerApplication {

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

}

halo-cloud-feign

  • pom.xml
  <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>
  • application.yml
server:
  port: 8080 #端口

spring:
  application:
    name: halo-cloud-fiegn #服務名稱

eureka:
  client:
    service-url:  #  eureka server 的地址, 咱們單實例模式就寫自己好了
      defaultZone: http://localhost:9090/eureka
    fetch-registry: true #表示是否將自己註冊到Eureka Server,默認是true。
    register-with-eureka: true #表示是否從Eureka Server獲取註冊信息,默認爲true。
  • FeignApplication.java
@EnableEurekaClient
@EnableFeignClients
@SpringBootApplication
public class FeignApplication {

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

}

halo-cloud-provider

  • pom.xml
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
  • application.yml
server:  # 服務端口
  port: 7070
spring:
  application:  # 應用名字,eureka 會根據它作爲服務id
    name: halo-cloud-provider

#  eureka配置
eureka:
  instance:
    hostname: spring-cloud-provider
  client:
    service-url:   #  eureka server 的地址, 咱們單實例模式就寫自己好了
      defaultZone:  http://localhost:9090/eureka
    register-with-eureka: true # 不向eureka server 註冊自己
    fetch-registry: true # 不向eureka server 獲取服務列表
  • ProviderApplication.java
@EnableEurekaClient
@SpringBootApplication
public class ProviderApplication {

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

}
  • ProviderController.java
    @RestController
    @RequestMapping("/provider")
    public class ProviderController {
    
        @Value("${server.port}")
        private Integer port;
    
        @GetMapping("/helloProvider")
        public String helloProvider(String name){
            return name+"正在調用provider端口:"+String.valueOf(port);
        }
    }

啓動測試

  • 註冊中心


  • 服務者測試


  • 消費者調用服務測試


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章