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);
        }
    }

启动测试

  • 注册中心


  • 服务者测试


  • 消费者调用服务测试


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