• SpringCloud OpenFeign


    SpringCloud OpenFeign

    1.OpenFeign 介绍

    1.OpenFeign 是什么

    1. OpenFeign 是个声明式 WebService 客户端,使用 OpenFeign 让编写 Web Service 客户端 更简单

    2. 它的使用方法是定义一个服务接口然后在上面添加注解

    3. OpenFeign 也支持可拔插式的编码器和解码器。

    4. Spring Cloud 对 OpenFeign 进 行 了 封 装 使 其 支 持 了 Spring MVC 标 准 注 解 和 HttpMessageConverters

    5. OpenFeign 可以与 Eureka 和 Ribbon 组合使用以支持负载均衡

    2.官网

    地址:openFeign官网

    3.Feign 和 OpenFeign 区别

    Feign

    1.Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端 2.Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。

    3.Feign的使用方式是:使用Feign的注解定义接口,调用服务注册中心的服务

    4.Feign支持的注解和用法请参考官方文档:https://github.com/OpenFeign/feign

    5.Feign本身不支持Spring MVC的注解,它有一套自己的注解

    6.引入依赖

       <dependencies>
          <dependency>
            <groupId>io.github.openfeigngroupId>
            <artifactId>feign-bomartifactId>
            <version>??feign.version??version>
            <type>pomtype>
            <scope>importscope>
          dependency>
        dependencies>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    OpenFeign

    1.OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如 @RequesMapping等等。

    2.OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口

    3.OpenFeign通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务

    4.引入依赖

    <dependency>
       <groupId>org.springframework.cloudgroupId>
       <artifactId>spring-cloud-starter-openfeignartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4

    精简一句话:OpenFeign 就是在 Feign 基础上做了加强 , 有些程序员为了方便,说 Feign 就是指的 OpenFeign

    2.OpenFeign-应用实例

    1.需求分析/图解

    – 示意图

    image-20220907225334073

    2.创建服务消费模块 -通过 OpenFeigen 实现远程调用的三种方式

    1.通过注册中心服务发现实现远程调用

    1.参考 member-service-consumer-80 创建 member-service-consumer-openfeign-80模块

    image-20220908195656799

    2.修改 pom.xml,引入openfeign依赖

    
    <dependency>
       <groupId>org.springframework.cloudgroupId>
       <artifactId>spring-cloud-starter-openfeignartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    3.创建 application.yml 内容如下:

    server:
      port: 80
    
    spring:
      application:
        name: member-service-consumer-openfeign-80
    
    #配置eureka-client
    eureka:
      client:
        #将自己注册到eureka-server
        register-with-eureka: true
        #表示从eureka-server获取注册信息
        #如果是单节点是可以不配置的,但如果是集群则必须配置为true,才能配合Ribbon实现负载均衡功能
        fetch-registry: true
        service-url:
          #表示将自己注册到哪个eureka-server
          defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4.创建主启动类

    //启用OpenFeignClient
    @EnableFeignClients
    @EnableEurekaClient
    @SpringBootApplication
    public class MemberConsumerOpenfeignApplication {
        public static void main(String[] args) {
            SpringApplication.run(MemberConsumerOpenfeignApplication.class,args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5.创建MemberFeignService.java,

    @Component
    @FeignClient(value = "MEMBER-SERVICE-PROVIDER")
    public interface MemberFeignService {
    
        //定义方法-远程调用接口
    
        /**
         * 1. 远程调用的方式是get
         * 2. 远程调用的url http://MEMBER-SERVICE-PROVIDER/member/get/{id}
         * 3. MEMBER-SERVICE-PROVIDER 就是服务提供方在Eureka Server 注册的服务
         * 4. openfeign 会根据负载均衡来决定调用10000/10002-默认是轮询
         * 5. 因为openfeign 好处是支持了springmvc注解 + 接口解耦
         *
         * openfeign是怎么样去远程调用的呢?
         * 1.注册中心通过MEMBER-SERVICE-PROVIDER服务注册名从注册中心去获取请求地址
         * 192.168.79.1:member-service-provider:10002 , 192.168.79.1:member-service-provider:10001
         * 2.通过springmvc注解 + 接口的方式实现远程调用
         * 3.openfeign接口地址需要和远程调用服务的地址一致
         */
        @GetMapping("/member/get/{id}")
        Result getMemberById(@PathVariable("id") Long id);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    6.创建MemberConsumerFeignController.java

    @RestController
    @RequiredArgsConstructor
    public class MemberConsumerFeignController {
    
        //装配MemberFeignService
        private final MemberFeignService memberFeignService;
    
        @GetMapping(value = "/member/consumer/openfeign/get/{id}")
        public Result getMemberById(@PathVariable("id") Long id) {
            return memberFeignService.getMemberById(id);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    7.启动测试

    openfeign默认轮询的方式实现负载均衡

    image-20220908202621540

    image-20220908202631602

    2.指定url地址,不经过Ribbon的服务选择,直接请求服务
    @Component
    /**
     * 指定远程调用url,用于固定访问某个服务不经过注册中心做服务的发现
     * value 和 name 的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。
     */
    @FeignClient(name = "member",url = "192.168.79.1:10001")
    public interface MemberFeignService {
        //定义方法-远程调用接口
        @GetMapping("/member/get/{id}")
        Result getMemberById(@PathVariable("id") Long id);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    3.动态url地址,不经过Ribbon的服务选择,直接请求服务
    /**
     * 1.指定远程调用url,用于固定访问某个服务不经过注册中心做服务的发现
     * 2.value 和 name 的作用一样,如果没有配置url那么配置的值将作为服务名称,用于服务发现。反之只是一个名称。
     * 3.contextId 当name/value相同时,指定不同的id来做区别
     * 也可以通过配置spring.main.allow-bean-definition-overriding=true来解决名称冲突的问题
     * 4.${member-provider.requesturl:} 从yml配置文件中读取
     */
    @FeignClient(name = "member",url = "${member-provider.requesturl:}",contextId = "dynamicUrl")
    @Component
    public interface MemberFeignDynamicUrlService {
    
        @GetMapping("/member/get/{id}")
        Result getMemberById(@PathVariable("id") Long id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.OpenFeign-日志配置

    1.基本介绍

    1. 说明: Feign 提供了日志打印功能,可以通过配置来调整日志级别,从而对 Feign 接口的 调用情况进行监控和输出

    2. 日志级别

      NONE∶默认的,不显示任何日志
      BASIC∶仅记录请求方法、URL、响应状态码及执行时间;

      HEADERS∶除了 BASIC中定义的信息之外,还有请求和响应的头信息;

      FULL∶除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。

    image-20220908210215823

    2.配置日志-应用实例

    1.创建配置类

    //@Configuration, OpenFeign全局日志配置
    @Configuration
    public class OpenFeignConfig {
        /**
         * 指定日志级别
         * @return
         */
        @Bean
        public Logger.Level logLevel(){
            return Logger.Level.FULL;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2.修改yml文件,指定openfeign日志级别

    logging:
      # openfeign接口远程调用过程打印信息 级别-Debug
      level:
        com.llp.springcloud.service.MemberFeignService: debug
    
    • 1
    • 2
    • 3
    • 4

    3.启动测试

    [MemberFeignService#getMemberById] 
    2022-09-08 21:28:18.980 DEBUG 25628 --- [p-nio-80-exec-1] c.l.s.service.MemberFeignService         : [MemberFeignService#getMemberById] {"code":"200","msg":"查询会员成功member-service-provider-10000","data":{"id":1,"name":"smith","pwd":"202cb962ac59075b964b07152d234b70","mobile":"123456789000","email":"smith@sohu.com","gender":1}}
    2022-09-08 21:28:18.980 DEBUG 25628 --- [p-nio-80-exec-1] c.l.s.service.MemberFeignService         : [MemberFeignService#getMemberById] <--- END HTTP (202-byte body)
    
    • 1
    • 2
    • 3

    4.OpenFeign-超时时间配置

    1.先看一个问题

    1.src\main\java\com\llp\springcloud\controller\MemberController.java新增一个测试超时的方法

    /**
     * 测试openfeign超时,默认1秒
     * @return
     */
    @GetMapping(value = "/member/timeout")
    public Result timeout() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Result.success();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2.修改src\main\java\com\llp\springcloud\service\MemberFeignService.java

    /**
     * 测试openfeign超时
     * @return
     */
    @GetMapping(value = "/member/timeout")
    Result timeout();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.member-service-provider-10000、member-service-provider-10002两个服务端添加对应的模拟超时的方法

    /**
     * 测试openfeign超时,默认1秒
     * @return
     */
    @GetMapping(value = "/member/timeout")
    public Result timeout() {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return Result.success();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    4.访问测试

    image-20220908214101611

    openfeign默认超时时间为1秒,即调用得到响应的时间超出1秒则会超时抛出异常

    2.设置超时时间

    1.设置Ribbon的超时时间(不推荐)

    设置很简单,在配置文件中添加如下设置:

    ribbon:
      #1. 设置feign客户端超时时间(openfeign默认支持ribbon)
      #2. ReadTimeout: 5000: 建立连接从服务提供方获取可用资源的所用的全部时间
      #3. 时间单位是毫秒
      ReadTimeout: 5000
      #两端连接所用时间
      ConnectionTimeout: 5000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    2.设置openFeign的超时时间(推荐)

    openFeign设置超时时间非常简单,只需要在配置文件中配置,如下:

    feign:
      client:
        config:
          ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
          default:
            connectTimeout: 5000
            readTimeout: 5000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    再次测试

    image-20220908215021856

    default设置的是全局超时时间,对所有的openFeign接口服务都生效

    但是正常的业务逻辑中可能涉及到多个openFeign接口的调用,如下图:

    image-20220908214818205

    那么上面配置的全局超时时间能不能通过呢?很显然是serviceA、serviceB能够成功调用,但是serviceC并不能成功执行,肯定报超时。

    此时我们可以给serviceC这个服务单独配置一个超时时间,配置如下:

    feign:
      client:
        config:
          ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
          default:
            connectTimeout: 5000
            readTimeout: 5000
          ## 为serviceC这个服务单独配置超时时间
          serviceC:
            connectTimeout: 30000
            readTimeout: 30000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这样A、B两个服务的超时时间就是50s,而C服务的超时时间就是30s了

    5.OpenFeign-指定公共请求参数

    1.创建FeignRequestHeaderInterceptor.java

    @Slf4j
    @RequiredArgsConstructor
    public class FeignRequestHeaderInterceptor implements RequestInterceptor {
    
        @Override
        public void apply(RequestTemplate requestTemplate) {
            try {
                Date currentTime = new Date();
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.ENGLISH);
                String date = simpleDateFormat.format(currentTime);
                requestTemplate.header("Date", date);
                requestTemplate.header("Address", "00000");
                //requestTemplate.body();
            } catch (Exception e) {
                log.error("会话Authorization异常", e);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2.在openfeign接口中指定配置类

    @Component
    //configuration是配置Feign配置类,在配置类中可以自定义Feign的Encoder、Decoder、LogLevel、Contract等。
    @FeignClient(value = "MEMBER-SERVICE-PROVIDER",configuration = {FeignRequestHeaderInterceptor.class})
    public interface MemberFeignService {
    
        //定义方法-远程调用接口
    
        /**
         * 1. 远程调用的方式是get
         * 2. 远程调用的url http://MEMBER-SERVICE-PROVIDER/member/get/{id}
         * 3. MEMBER-SERVICE-PROVIDER 就是服务提供方在Eureka Server 注册的服务
         * 4. openfeign 会根据负载均衡来决定调用10000/10002-默认是轮询
         * 5. 因为openfeign 好处是支持了springmvc注解 + 接口解耦
         * 

    * openfeign是怎么样去远程调用的呢? * 1.注册中心通过MEMBER-SERVICE-PROVIDER服务注册名从注册中心去获取请求地址 * 192.168.79.1:member-service-provider:10002 , 192.168.79.1:member-service-provider:10001 * 2.通过springmvc注解 + 接口的方式实现远程调用 * 3.openfeign接口地址需要和远程调用服务的地址一致 */ @GetMapping("/member/get/{id}") Result getMemberById(@PathVariable("id") Long id); /** * 测试openfeign超时 * @return */ @GetMapping(value = "/member/timeout") Result timeout(); }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    6.OpenFeign发送Https请求如何忽略SSL证书认证

    ​ 我们在使用opefeign框架去发送Https请求调用服务器接口时,如果服务器没有证书或者证书过期,但还是要https去调用,我们可以直接绕过SSL证书认证,否则就可能出现SSLHandshakeException异常情况,那么我们该如何使OpenFeign绕过SSL验证呢?

    FeginClient作为一个http请求工具,用来调用第三方接口,但是由于第三方接口常常是https开头,导致在调用的时候,触发SSL安全认证,这时候也就可以使用绕过认证的方法。

    这里我们就以Springcloud项目整合OpenFeign框架为例,我们只需将Feign的配置类修改如下即可:

    @Configuration
    public class FeignConfiguration {
     
        @Bean
        public CachingSpringLoadBalancerFactory cachingFactory(SpringClientFactory clientFactory) {
            return new CachingSpringLoadBalancerFactory(clientFactory);
        }
     
        @Bean
        @ConditionalOnMissingBean
        public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
                                  SpringClientFactory clientFactory) throws NoSuchAlgorithmException, KeyManagementException {
            SSLContext ctx = SSLContext.getInstance("SSL");
            X509TrustManager tm = new X509TrustManager() {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) {
                }
                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) {
                }
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                   //如果这里后续报空指针,就return new X509Certificate[0]
                    return null;
                }
            };
            ctx.init(null, new TrustManager[]{tm}, null);
            return new LoadBalancerFeignClient(new Client.Default(ctx.getSocketFactory(),
                    (hostname, session) -> true),
                    cachingFactory, clientFactory);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    更多细节可以参考:OpenFeign介绍和使用注意

  • 相关阅读:
    vivo 网络端口安全建设技术实践
    好文章推荐
    【Python】三目运算符(三元运算符)
    【嵌入式C】栈内存与printf,代码正确运行,删掉 printf 代码就崩溃了??
    元宇宙:打破虚拟与现实的边际
    踩坑指南:入门OpenTenBase之部署篇
    BUUCTF Reverse/[2019红帽杯]xx
    XSSFWorkbook Excel导出导入
    项目开发混淆从初识到理解
    618 火热来袭,网络安全书单推荐
  • 原文地址:https://blog.csdn.net/qq_44981526/article/details/126773142