精华内容
下载资源
问答
  • 主要介绍了Spring Cloud Feign组件实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Feign组件入门

    2020-03-22 16:02:10
    --引入SpringCloud整合的Feign组件--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId>...

    Feign的基本用法:

    1.导入依赖
    <!--引入SpringCloud整合的Feign组件-->
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
    2.配置调用接口:
    /**
     * 声明需要调用的微服务名称
     *  FeignClient:
     *      name:服务提供者的名称
     */
    @FeignClient(name = "service-product")
    public interface ProductFeignClient {
    
        /**
         * 配置需要调用的服务接口
         */
        @RequestMapping("/product/{id}")
        public Product findById(@PathVariable("id") Long id);
    }
    
    3.在启动类上激活Feign
    @SpringBootApplication
    @EntityScan("com.bjpowernode.order.entity")
    @EnableDiscoveryClient  //激活Eureka Client
    @EnableFeignClients   //激活Fegin
    public class OrderApplication {
    
        /**
         * 使用spring提供的RestTemplate发送请求到商品服务
         *      1.创建RestTemplate对象交给容器管理
         *      2.在使用的时候,调用其他方法完成
         */
    
        @LoadBalanced
        @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    }
    
    4.通过自动的接口调用远程微服务
    /**
     * 使用Feign组件完成服务的调用
     */
    @Controller("/order")
    public class OrderController {
    
    	//注入自定义的FeignClient接口
        @Autowired
        private ProductFeignClient productFeignClient;
    
        @RequestMapping("/buy/{id}")
        public Product findById(@PathVariable("id") Long id){
            Product product = productFeignClient.findById(id);
            return product;
        }
    }
    

    Feign和Ribbon的区别:

    Ribbon是一个客户端负载均衡,而Feign再Ribbon的基础上进行了再封装。

    Fegin的负载均衡:

    Feign内部已经封装了Ribbon,所以他可以在配置文件中使用Ribbon的负载均衡配置。
    #修改Ribbon的负载均衡策略 服务名  -- ribbon ---NFLoadBalancerRuleClassName : 策略
    service-product:
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule
        ConnectTimeout: 250 # Ribbon的连接超时时间
        ReadTimeout: 1000 # Ribbon的数据读取超时时间
        OkToRetryOnAllOperations: true # 是否对所有操作都进行重试
        MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
        MaxAutoRetries: 1 # 对当前实例的重试次数
    

    Feign的配置

    从Spring Cloud Edgware开始,Feign支持使用属性自定义Feign。对于一个指定名称的FeignClient(例如该Feign Client的名称为 feignName ),Feign支持如下配置项:
    feign:
    client:
    config:
    feignName: ##定义FeginClient的名称
    connectTimeout: 5000 # 相当于Request.Options
    readTimeout: 5000 # 相当于Request.Options
    # 配置Feign的日志级别,相当于代码配置方式中的Logger
    loggerLevel: full
    # Feign的错误解码器,相当于代码配置方式中的ErrorDecoder
    errorDecoder: com.example.SimpleErrorDecoder
    # 配置重试,相当于代码配置方式中的Retryer
    retryer: com.example.SimpleRetryer
    # 配置拦截器,相当于代码配置方式中的RequestInterceptor
    requestInterceptors:
     - com.example.FooRequestInterceptor
     - com.example.BarRequestInterceptor
    decode404: false
    
    • feignName:FeginClient的名称
    • connectTimeout : 建立链接的超时时长
    • readTimeout : 读取超时时长
    • loggerLevel: Fegin的日志级别
    • errorDecoder :Feign的错误解码器
    • retryer : 配置重试
    • requestInterceptors : 添加请求拦截器
    • decode404 : 配置熔断不处理404异常

    请求压缩

    Spring Cloud Feign 支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。通过下面的参数即可开启请求与响应的压缩功能:
    feign:
       compression:
       	request:
       		enabled: true # 开启请求压缩
       	response:
       		enabled: true # 开启响应压缩
    
    同时,我们也可以对请求的数据类型,以及触发压缩的大小下限进行设置:
    feign:
    	compression:
    		request:
    			enabled: true # 开启请求压缩
    			mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
    			min-request-size: 2048 # 设置触发压缩的大小下限
    

    日志级别

    在开发或者运行阶段往往希望看到Feign请求过程的日志记录,默认情况下Feign的日志是没有开启的。要想用属性配置方式来达到日志效果,只需在 application.yml 中添加如下内容即可:
    feign:
    	client:
    		config:
    		shop-service-product:
    		loggerLevel: FULL
    	logging:
    		level:
    		cn.itcast.order.fegin.ProductFeginClient: debug
    
    • logging.level.xx : debug : Feign日志只会对日志级别为debug的做出响应
    • feign.client.config.shop-service-product.loggerLevel : 配置Feign的日志Feign有四种
    日志级别:
    • NONE【性能最佳,适用于生产】:不记录任何日志(默认值)
    • BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、- 响应状态代码以及执行时间
    • HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
    • FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数
      据。
    展开全文
  • Spring Cloud Feign组件实现负载均衡 知道Feign组件,肯定知道还有一个Ribbon组件,我们来看一下这两个的区别。 Ribbon和Feign简单介绍 spring cloud的 Netflix 中提供了两个组件实现软负载均衡调用:ribbon 和 ...

    知道Feign组件,肯定知道还有一个Ribbon组件,我们来看一下这两个的区别。

    1. Ribbon和Feign简单介绍

      spring cloud的 Netflix 中提供了两个组件实现软负载均衡调用:ribbon 和 feign。

      Ribbon

      是一个基于 HTTP 和 TCP 客户端 的负载均衡的工具。
      它可以 在客户端 配置 RibbonServerList(服务端列表),使用 HttpClient 或 Sprig的RestTemplate模拟http请求,就跟我们平常调用hhtp接口的操作比较相似。Ribbon在调取服务的过程,使用的http的服务地址是注册中心的服务地址,多个相同的服务在注册中心注册,通过Ribbon,就可以实现对相同服务的负载均衡。

      Feign

      Feign是在 Ribbon的基础上进行了一次改进升级,是一个使用起来更加方便的 HTTP 客户端。
      其采用接口的方式, `只需要创建一个接口,在接口上面添加@FeignClient注解并指明要调取的服务提供者mingc,然后在接口方法上通过@RequestMapping注解加上服务提供者的接口地址,即可实现服务的调用 ,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求,通过接口抽象,使项目看起来层次比较清晰明了,所以大家一般都选择Feign是在。

      因为Feign本身里面就包含有了Ribbon,因为ribbon具有负载均衡功能,所以feign也继承了此功能。

    2. 负载均衡的实现

      在上篇博客中,最后我们已经实现了Feign的负载均衡。

      blog传送门

      项目代码传送门

      项目模块结构图

      在这里插入图片描述

      通过在cloud-consumer模块中加入负载均衡bean配置,即可实现默认的轮训负载均衡机制。

      package com.consumer.config;
      
      import org.springframework.cloud.client.loadbalancer.LoadBalanced;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.client.RestTemplate;
      
      /**
       * @author: yhl
       * @DateTime: 2019/12/9 13:37
       * @Description:
       */
      
      @Configuration
      public class ConfigBean {
          /**
           * 默认按顺序轮询
           * @return
           */
          @Bean
          @LoadBalanced
          public RestTemplate getRestTemplate() {
              return new RestTemplate();
          }
      }
      

      我们重点说一下负载均衡均衡策略的切换。

    3. 复杂均衡策略的切换

      先了解一下Ribbon中实现了那几种负载均衡算法。

      我们先看一下,Ribbon负载均衡设计类结构,首先在idea中找到抽象类AbstractLoadBalancerRule.java

      在类中的类名上右键选择查看类图

      在这里插入图片描述

      结构如下,可以看出是实现了两个规范接口。

      在这里插入图片描述

      我们继续查看AbstractLoadBalancerRule.java的实现类,在上面的类图AbstractLoadBalancerRule的框上鼠标右键,选择show implmentations,出现如下内容:

      在这里插入图片描述

      我们可以看出AbstractLoadBalancerRule有这么多实现类,通过类名,我们就可以看出这是负载均衡实现的算法类。

      介绍一下 Ribbon的几个比较常用的负载均衡实现

      策略类命名说明
      RandomRule随机策略随机选择 Server
      RoundRobinRule轮训策略按顺序循环选择 Server
      RetryRule重试策略在一个配置时问段内当选择 Server 不成功,则一直尝试选择一个可用的 Server
      BestAvailableRule最低并发策略逐个考察 Server,如果 Server 断路器打开,则忽略,再选择其中并发连接最低的 Server
      AvailabilityFilteringRule可用过滤策略过滤掉一直连接失败并被标记为 circuit tripped 的 Server,过滤掉那些高并发连接的 Server(active connections 超过配置的网值)
      ResponseTimeWeightedRule响应时间加权策略根据 Server 的响应时间分配权重。响应时间越长,权重越低,被选择到的概率就越低;响应时间越短,权重越高,被选择到的概率就越高。这个策略很贴切,综合了各种因素,如:网络、磁盘、IO等,这些因素直接影响着响应时间
      ZoneAvoidanceRule区域权衡策略综合判断 Server 所在区域的性能和 Server 的可用性轮询选择 Server,并且判定一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中的所有 Server

      具体可参考:https://www.jianshu.com/p/186b4ceea6fc, 感谢作者。

      Ribbon默认使用的是RoundRobinRule轮训策略。

      那么在我们在项目中到底如何切换自己想要的均衡策略模式呢?我们尝试实现其中的一种

      在cloud-consumer模块中的application.文件中加入如下配置:

      cloud-service:
        ribbon:
          NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
      

      cloud-service为服务提供者在注册中心的服务名称。参数value为复杂均衡实现类在Ribbon包中的路径,如RandomRule随机策略的类路径类为:com.netflix.loadbalancer.RandomRule。切换的话只需要更改其他的算法实现类的类路径。(个人觉得这个方法好蹩脚,必须知道负载均衡相关的算法类)

      还有其他的配置方式,具体的请参考:https://blog.csdn.net/wo18237095579/article/details/83384134
      感谢作者。

    4. 实现自定义负载均衡策

      创建自定义策略类,继承抽象类AbstractLoadBalancerRule,重写choose方法为自己的负载均衡逻辑,在配置类中添加下bean配置。

      @Bean
      public IRule myRule()
      {
          return new CustomeRule(); //自定义负载均衡规则
      }
      

      具体可参考:https://www.cnblogs.com/yufeng218/p/10952724.html,感谢作者。

    展开全文
  • springcloud学习笔记之Feign组件

    万次阅读 2019-07-06 17:02:24
    作者从四个方面阐述springClound的feign组件 1、feign的概念以及使用实例 2、通过@EnableFeignClient注解 分析了feign和spring结合的原理 3、通过@FeignClient注解,分析feign如何使用 希望能给你在学习spring...

    目录

    一、feign简介应用

          1、feign的概念

          2、feign的使用

    二、feign原理分析

          1、前言

          2、@EnableFeignClients注解

      2.1、@EnableFeignClients

      2.2、FeignClientsRegistrar类

      2.3、加载feign的配置信息

      2.4、注册FeignClient

      2.5、registerFeignClient

    3、@FeignClient注解

        3.1 FeignClient注解使用

        3.2 @FeignClient的属性

        3.3 @FeignClient源码分析

     



    一、feign简介应用

          1、feign的概念

                 Feign是一个声明性的Web服务客户端。它使编写Web服务客户端变得更容易。feigin是一种模板化,声明式的http客户端,feign可以通过注解绑定到接口上来简化Http请求访问。与当我们访问别的服务端口的时候 大部分使用httpclient等请求进行调用不同,在eureka注册的服务,我们可以使用Feign 声明接口的形式来进行相关服务的调用,并提供了失败回退(其实是Hystrix组件的使用)。Feign只是一个便利的rest框架,简化调用,最后还是通过ribbon在注册服务器中找到服务实例,然后对请求进行分配。

          2、feign的使用

    •        maven依赖          
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-feign</artifactId>
    </dependency>
    •      主项目中添加@EnableFeignClients
    @SpringBootApplication
    //扫描项目下所有使用@FeignClient注解修饰的接口
    @EnableFeignClients
    @EnableEurekaClient
    public class FeignApplication {
    
    	public static void main(String[] args) {
    
    		SpringApplication.run(FeignApplication.class, args);
    	}
    
    }
    
    •    使用feign调用微服务
    //使用feignclien注解和SpringMVC相关的常用注解 声明一个feign接口 调用微服务信息
    @FeignClient(value = "service-ribbon",url = "https://api.github.com",decode404 = false,
            fallback = MyFallback.class, fallbackFactory = MyFallBackFactory.class )
    public interface SayHiFeign {
    
        @RequestMapping("/hi", method = RequestMethod.GET)
        String sayHi(@RequestParam(name="name",required = true) String name);
    }
    

      如上便完成了使用feign完成别的为服务调用,是不是很简单。点击下载demo源码 feign组件使用demo

    二、feign原理分析

          1、前言

                     通过如上的简单介绍我们大致了解了feign的概念以及如何在项目中进行使用,通过上面的观察以及使用,我们发现feign组件在springclound项目中使用是如此只简单:只需在项目的主启动类使用@EnableFeignClients注解,在服务接口类中使用@FeignClient修饰。下面我们就从这两个注解入手揭开feign的神秘面纱(貌似话说的有点大)。

          2、@EnableFeignClients注解

                        为了方便理解,我们在这里先不给出结论,直接从源码中一步一步分析代码,最后再给出结论。

                 2.1、@EnableFeignClients

    //运行时保留
    @Retention(RetentionPolicy.RUNTIME)
    //该注解用于修饰描述类、接口(包括注解类型) 或enum声明
    @Target(ElementType.TYPE)
    //可以生产api doc
    @Documented
    //这个比较重要使用注解修饰的项目 需要先初始化FeignClientsRegistrar该类 
    @Import(FeignClientsRegistrar.class)
    public @interface EnableFeignClients {
    
    	//basePackages的别名
    	String[] value() default {};
    
        //指定需要扫描的包名列表
    	String[] basePackages() default {};
    
        //指定需要扫描的class列表信息
    	Class<?>[] basePackageClasses() default {};
    
    	//feign调用的配置信息类 该对象非常重要,
        //包含FeignClient需要的重试策略,超时策略,日志等配置,
        //如果某个服务没有设置, 则读取默认的配置。
    	Class<?>[] defaultConfiguration() default {};
    
    	//直接指定FeignClient注解修饰的class
    	Class<?>[] clients() default {};

          该注解 用来开启 Feign,所以其属性主要是指定要扫描的包名类名 FeignClient列表(value属性,basePackages属性,basePackageClasses属性,clients属性),以及相关的配置信息(defaultConfiguration),这些并非我们关注的重点 在该注解类上有个使用@Import注解引入FeignClientsRegistrar.class 的实体类 其实该类是实现feign调用的部分功能(前期准备)的实现,下面让我们来分析一下

    FeignClientsRegistrar类

       2.2、FeignClientsRegistrar类

    class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
          ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

              通过名字可以看出该类是一个注册器,该类实现了 ImportBeanDefinitionRegistrar 通过扫描某个特性的类,将bean注册到IOC中。他的生命周期方法是registerBeanDefinitions ,Spring 通过调用其 registerBeanDefinitions 方法来获取其提供的 bean definition。

    //生命周期的方法
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
        	BeanDefinitionRegistry registry) {
        //注册feign 相关的特性 配置信息
    	registerDefaultConfiguration(metadata, registry);
        //注册FeignClient 对象
    	registerFeignClients(metadata, registry);
    }

    上面开启feign主要分两大部分:

    •  注册feign的配置信息,比如重试机制,日志配置
    •  注册所有使用@FeigenClient修饰的类注册

     2.3、加载feign的配置信息

    //注册配置信息
    private void registerDefaultConfiguration(AnnotationMetadata metadata,
    			BeanDefinitionRegistry registry) {
            //获取EnableFeignClients注解的元数据信息
    		Map<String, Object> defaultAttrs = metadata
    				.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
    
            //判断是否存在defaultConfiguration 属性信息
    		if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
    			String name;
    			if (metadata.hasEnclosingClass()) {
    				name = "default." + metadata.getEnclosingClassName();
    			}
    			else {
    				name = "default." + metadata.getClassName();
    			}
                //注册defaultConfiguration 对应的属性信息类 ,如果为空则使用默认的配置 
                //FeignAutoConfiguration
                //最终将配置类解析成一个BeanDefinition类注入到spring中
    			registerClientConfiguration(registry, name,
    					defaultAttrs.get("defaultConfiguration"));
    		}
    	}
    如上主要是从启动类的@EnableFeignClients 中获取defaultConfiguration属性中用户自定义的配置信息,如果没有则使用默认的配置信息类FeignAutoConfiguration,最终将其包装成BeanDefinition类注册到spring容器中(代码比较繁琐,个人只贴到这里)。配置中心主要提供了feign 的功能特性,该配置信息是适用于@FeignClient注解的全局配置,也可以在@FeignClient的configuration属性做单独的配置。该配置主要包含熔断器、失败重试、超时策略、日志配置等。
    

     2.4、注册FeignClient

       //注册FeigenClient
        public void registerFeignClients(AnnotationMetadata metadata,
                                         BeanDefinitionRegistry registry) {
            //获取类扫描组件
            ClassPathScanningCandidateComponentProvider scanner = getScanner();
            //添加资源加载服务类 提供加载指定目录下的资源信息 便于后面的类扫描
            scanner.setResourceLoader(this.resourceLoader);
    
            Set<String> basePackages;
    
            //获取EnableFeignClients注解的属性信息 其中可能包含需要扫描的包名或者class信息
            Map<String, Object> attrs = metadata
                    .getAnnotationAttributes(EnableFeignClients.class.getName());
            //创建扫描过滤规则 只扫描包含FeignClient注解修饰的类
            AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(
                    FeignClient.class);
            //获取注解中包含client 属性  如果有则不进行包名扫描 直接遍历存在的client 进行注册
            final Class<?>[] clients = attrs == null ? null
                    : (Class<?>[]) attrs.get("clients");
            if (clients == null || clients.length == 0) {
                //为扫描类设置上面创建的只扫描FeignClient注解的扫描规则
                scanner.addIncludeFilter(annotationTypeFilter);
                //获取扫描的包名
                basePackages = getBasePackages(metadata);
            }
            else {
                //有client 将client所在的包加入的扫描包列表中 添加新的一个过滤规则
                final Set<String> clientClasses = new HashSet<>();
                basePackages = new HashSet<>();
                for (Class<?> clazz : clients) {
                    basePackages.add(ClassUtils.getPackageName(clazz));
                    clientClasses.add(clazz.getCanonicalName());
                }
                AbstractClassTestingTypeFilter filter = new AbstractClassTestingTypeFilter() {
                    @Override
                    protected boolean match(ClassMetadata metadata) {
                        String cleaned = metadata.getClassName().replaceAll("\\$", ".");
                        return clientClasses.contains(cleaned);
                    }
                };
                scanner.addIncludeFilter(
                        new FeignClientsRegistrar.AllTypeFilter(Arrays.asList(filter, annotationTypeFilter)));
            }
            //遍历包扫描列表
            for (String basePackage : basePackages) {
                //通过报名获取对应的查找出来的FeignClient注解修饰的接口的ScanGeneric的 BeanDefinition描述
                Set<BeanDefinition> candidateComponents = scanner
                        .findCandidateComponents(basePackage);
                for (BeanDefinition candidateComponent : candidateComponents) {
                    if (candidateComponent instanceof AnnotatedBeanDefinition) {
                        // verify annotated class is an interface
                        AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                        //获取其中的元数据信息
                        AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                        Assert.isTrue(annotationMetadata.isInterface(),
                                "@FeignClient can only be specified on an interface");
                        //从所有的元数据中获取到FeignClient注解相关的属性信息 url  name fallBack fallbackFactory decode404等
                        Map<String, Object> attributes = annotationMetadata
                                .getAnnotationAttributes(
                                        FeignClient.class.getCanonicalName());
    
                        String name = getClientName(attributes);
                        //attributes中局部配置信息注册和如上说的全局配置注册流程一致
                        registerClientConfiguration(registry, name,
                                attributes.get("configuration"));
                        //根据元数据 将使用FeignClient修饰的类解析成BeanDefinition
                        registerFeignClient(registry, annotationMetadata, attributes);
                    }
                }
            }
        }

     registerFeignClients方法主要是通过扫描指定包下的所有使用@FeignClient修饰的接口类列表(如果@EnableFeignClients中配置了clients属性,则扫描出来的bean只有在clients中配置的那些),遍历这些类进行FeignClient的注册以及局部配置信息的注册。下面继续关注registerFeignClient()方法如何实现注册FeignClient

    2.5、registerFeignClient

    private void registerFeignClient(BeanDefinitionRegistry registry,
    			AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
    		String className = annotationMetadata.getClassName();
    		BeanDefinitionBuilder definition = BeanDefinitionBuilder
    				.genericBeanDefinition(FeignClientFactoryBean.class);
    		validate(attributes);
    		definition.addPropertyValue("url", getUrl(attributes));
    		definition.addPropertyValue("path", getPath(attributes));
    		String name = getName(attributes);
    		definition.addPropertyValue("name", name);
    		definition.addPropertyValue("type", className);
    		definition.addPropertyValue("decode404", attributes.get("decode404"));
    		definition.addPropertyValue("fallback", attributes.get("fallback"));
    		definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
    		definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
    
    		String alias = name + "FeignClient";
    		AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
    
    		boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null
    
    		beanDefinition.setPrimary(primary);
    
    		String qualifier = getQualifier(attributes);
    		if (StringUtils.hasText(qualifier)) {
    			alias = qualifier;
    		}
    
    		BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,
    				new String[] { alias });
    		BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
    	}

     这个方面比较简单 只是获取FeignClient注解的元数据将其设置到BeanDefinitionBuilder 用于构造BeanDefinition类并注册到spring中。我们需要注册的是程序获取BeanDefinition的类是FeignClientFactoryBean(该类看名字可以得出是FeignClient工程类 i因为修饰的类是接口类 所有是创建FeignClient代理 这点我们在分析@FeignClient注解的时候讲解)

    补充:BeanDefinition  Spring容器启动的过程中,会将Bean解析成Spring内部的BeanDefinition结构
    其不仅包含bean的香港信息 还包含其他关于描述该bean特性的信息 例如scode 懒加载等spring赋予的特性信息
    里面类名、scope、属性、构造函数参数列表、依赖的bean、是否是单例类、是否是懒加载等,其实就是将Bean的定义信息存储到这个BeanDefinition相应的属性中,后面对Bean的操作就直接对BeanDefinition进行,例如拿到这个BeanDefinition后,可以根据里面的类名、构造函数、构造函数参数,使用反射进行对象创建。’

    总结:

      到此开启Feign,就完成了我们总结一下

    Feign的注册一共分为一下几步:

    • 扫描@EnableFeignClients注解,如果有defaultConfiguration属性配置,则将configuration注册到BeanDefinition中,如果不指定的话,spring 提供的默认配置是FeignClientsConfiguration。
    • 扫描 basePackage 下面所有包含了 FeignClient 注解的类
    • 如果@EnableFeignClients中配置了clients属性,则扫描出来的bean只有在clients中配置的那些
    • 循环扫描@FeignClient注解,如果配置了configuration,则将configuration按照 1 注册打BeanDefinition中,也就是说Feign既支持用作统一的默认的Config作为全局配置,也可以分别在@FeignClient中单独配置configuration 作为局部配置。
    • 将@FeignClient中的其他配置设置到FeignClientFactoryBean中。

    3、@FeignClient注解

            3.1 FeignClient注解使用

    //使用feignclien注解和SpringMVC相关的常用注解 声明一个feign接口 调用微服务信息
    @FeignClient(value = "service-ribbon",url = "https://api.github.com",decode404 = false,
            fallback = MyFallback.class, fallbackFactory = MyFallBackFactory.class )
    public interface SayHiFeign {
    
        @RequestMapping("/hi", method = RequestMethod.GET)
        String sayHi(@RequestParam(name="name",required = true) String name);
    }
    

          3.2 @FeignClient的属性

                     属性

                                 相关描述

                  name/value     服务名称(在注册中心注册的服务名称)(两者其中之一必填)

                        url

         硬编码存在的url地址 如果该地址存在 则不通过服务名称查找服务
                   decode404      对于404的错误 是直接抛出异常(图1),还是将异常信息解码响应(图2)
                      config      FeignClientsConfiguration feign客户端 提供encode编码器 decode解码器 contract连接器
                    fallback      服务调用失败的时候会回调该类下同名的方法,用于失败的服务降级等操作
                 fallbackFactory    失败回调工厂类生产fallback相关的工厂类作用与fallback一样
    •       decode404

    fallback 失败回调类

    /**
     *失败回调类 实现需要失败回调的接口 从而保证其有与实现类一样的方法
     */
    @Component
    public class MyFallback implements GitHubApiFeign {
        Logger logger = LoggerFactory.getLogger(MyFallback.class);
        @Override
        public String searchRepositories(String queryStr) {
            logger.info("失败回调操作");
            return null;
        }
        @Override
        public String searchRepositoriea(String queryStr) {
            logger.info("失败回调操作");
            return null;
        }
    }
    
    • fallbackFactory 是被回调工厂类
    /**
     * 失败回调的工厂类 没有特殊之处 只是针对上述的失败类使用工厂模式创建而已
     */
    @Component
    public class MyFallBackFactory implements FallbackFactory<GitHubApiFeign> {
        private final MyFallback myFallback;
        public MyFallBackFactory(MyFallback myFallback) {
            this.myFallback = myFallback;
        }
        @Override
        public GitHubApiFeign create(Throwable cause) {
            //打印下异常
            System.out.println("失败回调的工厂");
            cause.printStackTrace();
            return myFallback;
        }
    }
    

      3.3 @FeignClient源码分析

            在 2.5 registerFeignClient中我们发现是将Feign的包装成BeanDefinition类注册到spring容器中,同时我们也可以明确的知道该包装成BeanDefinition的类为FeignClientFactoryBean类。在上面的篇幅中我们分析了Feign如何在Spring容器中进行注册的,下面我们就从FeignClientFactoryBean来分析一下Feign的调用过程(中间可能会简单涉及Ribbon和Hystrix的介绍)。

    •  getObject()方法   

     FeignClientFactoryBean实现了FactoryBean所以该类在spring中使用的时候会调用其getObject()方法返回指定的bean对象

    @Override
    	public Object getObject() throws Exception {
    		//从应用中获取Feign上下文环境信息 FeignContext中默认使用FeignClientsConfiguration中的配置信息
    		//不如feign的Decoder解码 Encoder编码 Retryer重试次数 logger日志等 以及各种Feign HystrixFeign(带有熔断作用的Feign)等
    		FeignContext context = applicationContext.getBean(FeignContext.class);
    		//根据FeignContext 上下文环境以构建形式创建Feign 具体单独分析
    		Feign.Builder builder = feign(context);
    
    		//判断@FeignClient中的url属性是否有值 没有值则走Eureka注册中心
    		if (!StringUtils.hasText(this.url)) {
    			//如下是获取对应的请求url 如果与Eureka结合使用则是注册中心的服务名称类型的url
    			//这个做url的规范化处理
    			String url;
    			if (!this.name.startsWith("http")) {
    				url = "http://" + this.name;
    			}
    			else {
    				url = this.name;
    			}
    			url += cleanPath();
    			//使用负载均衡以及Hystrix 对请求进行相关的调用
    			return loadBalance(builder, context, new Target.HardCodedTarget<>(this.type,
    					this.name, url));
    		}
    		//有url属性值 则直接请求该url
    		if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
    			this.url = "http://" + this.url;
    		}
    		String url = this.url + cleanPath();
    		//从Feign的上下文环境中获取Feign的client(主要用作请求的执行)
    		Client client = getOptional(context, Client.class);
    		//判断如果client的请求是存在且为LoadBalancerFeignClient(具备负载请求的客户端) 则将客户端转换
    		//并设置入Fiegn对象中
    		if (client != null) {
    			if (client instanceof LoadBalancerFeignClient) {
    				// not lod balancing because we have a url,
    				// but ribbon is on the classpath, so unwrap
    				client = ((LoadBalancerFeignClient)client).getDelegate();
    			}
    			builder.client(client);
    		}
    		//获取对应的Targeter类 该类的实现有两种一种是DefaultTargeter类(不做任何处理 仅仅是Feign target调用)
    		//另一种是HystrixTargeter类 使用给feign添加了Hystrix的熔断 失败回调的功能
    		Targeter targeter = get(context, Targeter.class);
    		//这个是我们的核心方法 用来创建Feign的具体代理对象
    		return targeter.target(this, builder, context, new Target.HardCodedTarget<>(
    				this.type, this.name, url));
    	}
    • Feign.builder的构建

               将Feign环境中的配置信息(编解码对象,重试 ,client客户端,Targeter)获取到以构建的形式构造Feign对象

    	protected Feign.Builder feign(FeignContext context) {
    		//这个的get() getOptional()方法都是从Feign的上下文中根据获取对应的对象信息
    		//获取日志
    		FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
    		Logger logger = loggerFactory.create(this.type);
    
    		// @formatter:off
    		//设置 日志 请求的编码对象 解码对象 Contract请求的协议信息
    		Feign.Builder builder = get(context, Feign.Builder.class)
    				// required values
    				.logger(logger)
    				.encoder(get(context, Encoder.class))
    				.decoder(get(context, Decoder.class))
    				.contract(get(context, Contract.class));
    		// @formatter:on
    
    		//可选操作
    		//设置日志等级
    		Logger.Level level = getOptional(context, Logger.Level.class);
    		if (level != null) {
    			builder.logLevel(level);
    		}
    		//重试
    		Retryer retryer = getOptional(context, Retryer.class);
    		if (retryer != null) {
    			builder.retryer(retryer);
    		}
    		//请求返回错误信息的解码对象
    		ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
    		if (errorDecoder != null) {
    			builder.errorDecoder(errorDecoder);
    		}
    		//连接超时,读取超市的配置信息
    		Request.Options options = getOptional(context, Request.Options.class);
    		if (options != null) {
    			builder.options(options);
    		}
    		//请求拦截器
    		Map<String, RequestInterceptor> requestInterceptors = context.getInstances(
    				this.name, RequestInterceptor.class);
    		if (requestInterceptors != null) {
    			builder.requestInterceptors(requestInterceptors.values());
    		}
             //404请求不到情况下错误信息的编码处理
    		if (decode404) {
    			builder.decode404();
    		}
    		//构建成功返回
    		return builder;
    	}

        使用@FeignClient注解修饰的Feign接口被包装成Target(目标对象),被Targeter(瞄准者)所调用

    • loadBalance
    protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
                                HardCodedTarget<T> target) {
        // 1.获取Client的实现类,默认为LoadBalancerFeignClient类
        // 实现在FeignRibbonClientAutoConfiguration中
        Client client = getOptional(context, Client.class);
        if (client != null) {
            // 2.将LoadBalancerFeignClient包装到Feign.Builder
            builder.client(client);
            
            // 3.获取ApplicationContext中的Targeter实现
            // 默认实现为HystrixTargeter,实现在FeignAutoConfiguration类中
            Targeter targeter = get(context, Targeter.class);
            
            // 4.重点在这里
            // 我们来看下这个方法
            return targeter.target(this, builder, context, target);
        }
        ...
    }
    

     

    • Targeter 的target方法

    请求的处理 有url不走负载请求,没有url 则配合Eureka使用进行请求的负载均衡,但是无论@FeignClient的url是否有值 最终处理逻辑均相似 获取Targeter并调用其中的target()方法 唯一不同是配合Eureka targeter为HystrixTarger ,直接请求url的是使用DefaultTargerter对象。

    	public <T> T target(FeignClientFactoryBean factory, Feign.Builder feign, FeignContext context,
    						Target.HardCodedTarget<T> target) {
    		//判断如果该feign 不是HystrixFeign 则直接调用
    		if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
    			return feign.target(target);
    		}
    		//是HystrixFeign 将其转换出来
    		feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder) feign;
    
    		SetterFactory setterFactory = getOptional(factory.getName(), context,
    				SetterFactory.class);
    		if (setterFactory != null) {
    			builder.setterFactory(setterFactory);
    		}
    		//获取失败的回调对象 如果存在请求调用的时候设置失败回调类
    		Class<?> fallback = factory.getFallback();
    		if (fallback != void.class) {
    			return targetWithFallback(factory.getName(), context, target, builder, fallback);
    		}
    		//获取失败的回调对象的工厂类 如果存在请求调用的时候设置失败回调工厂类
    		Class<?> fallbackFactory = factory.getFallbackFactory();
    		if (fallbackFactory != void.class) {
    			return targetWithFallbackFactory(factory.getName(), context, target, builder, fallbackFactory);
    		}
            //否则直接调用
    		return feign.target(target);
    	}
    •     targetWithFallback和targetWithFallbackFactory方法

          在上面的分析中我们看到了是@FiegnClient 注解的属性fallback或fallbackFactory对应的调用targetWithFallback或targetWithFallbackFactory,其实两者的逻辑处理相似 前者获取其中的回调实例,后者获取其中的回调工厂实例,但是最终还都是调用 1、builder.target(target, fallback);  2、builder.target(target, fallbackFactory);

    •   builder.target() feign.target()

           如下Feign 和HystrixFeign提供众多的target方法

    Hystrix 提供了四种target方法
    public <T> T target(Target<T> target, T fallback) {
                return this.build(fallback != null ? new feign.hystrix.FallbackFactory.Default(fallback) : null).newInstance(target);
            }
    
            
    public <T> T target(Target<T> target, FallbackFactory<? extends T> fallbackFactory) {
                return this.build(fallbackFactory).newInstance(target);
            }
    
            
    public <T> T target(Class<T> apiType, String url, T fallback) {
                return this.target(new HardCodedTarget(apiType, url), (Object)fallback);
            }
    
            
    public <T> T target(Class<T> apiType, String url, FallbackFactory<? extends T> fallbackFactory) {
                return this.target(new HardCodedTarget(apiType, url), (FallbackFactory)fallbackFactory);
            }
    
    
    feign提供了五中target方法
        public <T> T target(Class<T> apiType, String url) {
          return target(new HardCodedTarget<T>(apiType, url));
        }
    
        public <T> T target(Target<T> target) {
          return build().newInstance(target);
        }
    

    如上这些方法都是调用其build().newInstance()方式,同时也是我们需要分析的下面我们来看一下build()方法

      public Feign build() {
          //获取SynchronousMethodHandler的工厂类 用来创建SynchronousMethodHandler对象
          //而我们所有的Feign接口方法都被包装成该对象SynchronousMethodHandler
          SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
              new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
                                                   logLevel, decode404);
          ParseHandlersByName handlersByName =
              new ParseHandlersByName(contract, options, encoder, decoder,
                                      errorDecoder, synchronousMethodHandlerFactory);
          //真正创建ReflectiveFeign 同时后面的newInstance会调用该对象的实现。
          return new ReflectiveFeign(handlersByName, invocationHandlerFactory);
        }

      如上创建ReflectiveFeign对象 我们需要看一下该类的newInstance()方法。

    public <T> T newInstance(Target<T> target) {
    		//targetToHandlersByName 见名知义 从目标对象(使用@FeignClient修饰的接口类)中获取其中所有的接口方法 放到map中
    		//key 为方法的全限定名称,value 为MethodHandler的实现类 feign调用是SynchronousMethodHandler类
    		//在这里其实是将feign的所有方法包SynchronousMethodHandler 调用的时候会执行其invoke()方法
    		Map<String, InvocationHandlerFactory.MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
    		Map<Method, InvocationHandlerFactory.MethodHandler> methodToHandler = new LinkedHashMap<Method, InvocationHandlerFactory.MethodHandler>();
    		List<DefaultMethodHandler> defaultMethodHandlers = new LinkedList<DefaultMethodHandler>();
            
    		//遍历目标类的所有接口方法 并将其存放入methodToHandler方法处理器集合中
    		for (Method method : target.type().getMethods()) {
    			if (method.getDeclaringClass() == Object.class) {
    				continue;
    			} else if(Util.isDefault(method)) {
    				DefaultMethodHandler handler = new DefaultMethodHandler(method);
    				defaultMethodHandlers.add(handler);
    				methodToHandler.put(method, handler);
    			} else {
    				methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));
    			}
    		}
    		//调用SynchronousMethodHandlerFactory 的create方法 创建InvocationHandler 的实现类
    		//HystrixInvocationHandler(JDK动态代理)
    		InvocationHandler handler = factory.create(target, methodToHandler);
    		//创建代理对象
    		T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
    
    		for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {
    			defaultMethodHandler.bindTo(proxy);
    		}
    		//将创建的代理对象返回
    		return proxy;
    	}

       如上代码将为feign接口使用jdk动态代理创建了一个代理对象HystrixInvocationHandler。所以相关的对feign接口的调用触发HystrixInvocationHandler对象的invoke()方法,分析到这里我们对feign的调用逻辑大致清晰了,所有Feign接口类会使用创建Feign的代理对象,所有接口方法调用都 HystrixInvocationHandler的invoke()方法

    • HystrixInvocationHandler的invoke()方法
    
    	public Object invoke(final Object proxy, final Method method, final Object[] args)
    			throws Throwable {
    		// early exit if the invoked method is from java.lang.Object
    		// code is the same as ReflectiveFeign.FeignInvocationHandler
    		//equals hashCode toString 单独设置
    		if ("equals".equals(method.getName())) {
    			try {
    				Object otherHandler =
    						args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
    				return equals(otherHandler);
    			} catch (IllegalArgumentException e) {
    				return false;
    			}
    		} else if ("hashCode".equals(method.getName())) {
    			return hashCode();
    		} else if ("toString".equals(method.getName())) {
    			return toString();
    		}
            //对于feign接口请求 结合Hystrix组件 使用新建线程来单独执行,防止服务之间调用时候某些服务不可用时候的服务雪崩
    		HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) {
    			@Override
    			protected Object run() throws Exception {
    				try {
    					//dispatch的类为Map<String, InvocationHandlerFactory.MethodHandler> 包含一个Figen接口中的所有接口方法
    					// 这些接口方法被包装成了MethodHandler 最终该童虎方法名获取到对应的MethodHanlder 调用其invoke()方法
    					return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
    				} catch (Exception e) {
    					throw e;
    				} catch (Throwable t) {
    					throw (Error) t;
    				}
    			}
    
    			//失败回调
    			@Override
    			protected Object getFallback() {
    				....
    				try {
    					Object fallback = fallbackFactory.create(getExecutionException());
    					//失败回调方法被封装成了MethodHandler 如果正常调用是被则 调用失败的MethodHandler的invoke方法
    					Object result = fallbackMethodMap.get(method).invoke(fallback, args);
    				....
    			}

     如上Feign接口调用是其实是根据方法名获取对应的MethodHandler类确定的说是SynchronousMethodHandler类的invoke()

    同时该方法的调用是通过Hystrix组件来实现每个方法调用都创建线程来单独调用。

    下面来看一下SynchronousMethodHandler的invoke()方法

    	public Object invoke(Object[] argv) throws Throwable {
    		//feign之间的调用是基于HTTP请求 所以在创建Resquest请求
    		RequestTemplate template = buildTemplateFromArgs.create(argv);
    		Retryer retryer = this.retryer.clone();
    		while (true) {
    			try {
    				//执行请求()
    				return executeAndDecode(template);
    			} catch (RetryableException e) {
    				retryer.continueOrPropagate(e);
    				if (logLevel != Logger.Level.NONE) {
    					logger.logRetry(metadata.configKey(), logLevel);
    				}
    				continue;
    			}
    		}
    	}
    
    	Object executeAndDecode(RequestTemplate template) throws Throwable {
    		//获取请求信息
    		Request request = targetRequest(template);
    
    		if (logLevel != Logger.Level.NONE) {
    			logger.logRequest(metadata.configKey(), logLevel, request);
    		}
    
    		Response response;
    		long start = System.nanoTime();
    		try {
    			//使用客户端执行请求 Feign默认集成了Ribbion 所以这里请求是带有负载均衡功能的
    			response = client.execute(request, options);
    			// ensure the request is set. TODO: remove in Feign 10
    			response.toBuilder().request(request).build();
    			//后面是将响应信息解码封装 然后返回
    			.....
    	}

      如上invoke()调用其实是封装http请求 并发送请求,又因为这里feign和Ribbon默认集成,所以请求是带有负载功能的请求。到此feign组件分析结束。

    • 总结
    1.        @EnableFeignClients将所有使用@FeignClientFeignClientFactoryBean 在spring注册为BeanDefinition类,则使用初始化该类调用其getObject()方法
    2.     使用JDK动态代理针对Feign接口生成代理对象
    3.    中间会有和Hystrix、Ribbon调用。
    4.  具体方法的调用是MethodHandler的invoke()

     

       Feign分析到此结束,个人能力有限,有不足之处,希望大家不吝赐教,如果帮到你的话,请点赞或评论,你的支持是我继续更博的动力。同时也谢谢你这么好看还来看我的文章。

      

     

     

     

     

     

     

     

     

     

     

    展开全文
  • SpringCloud之Feign组件

    2020-05-20 11:46:29
    之前我们使用ribbon是通过微服务的名字调用,而在开发中大家都习惯面向接口编程,因此通过接口和注解调用的feign组件应用也非常广泛 Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置,类似于之前Dao...

    目录

    什么是Feign

    回顾基于Http的RestTemplate远程调用方式

    Feign的使用


     

    什么是Feign

     

    Feign的目的是让编写Java Http请求客户端变得更容易。之前我们用Ribbon+RestTemplate对http请求进行封装,形成一套模板化的调用方法。但实际开发中,由于对服务依赖的调用不只一处,往往一个接口被多次调用所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。Feign正是在此基础上的封装组件。在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置,类似于之前Dao接口上的Mapper注解,现在是在微服务接口类上标注一个Feign注解即可。这种方式简化了Ribbon的同时,自动封装了服务调用客户端的代码量

    Feign集成了Ribbon。通过轮询实现了客户端的负载均衡

     

     

    回顾基于Http的RestTemplate远程调用方式

     

    之前我们单纯使用RestTemplate需要每个请求都拼接url+参数+类文件。

    https://blog.csdn.net/Delicious_Life/article/details/106216290 

     

     

    Feign的使用

     

    在调用方和被调用方项目中分别导入feign的包

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-feign</artifactId>
                <version>1.4.6.RELEASE</version>
            </dependency>

    在调用方中新建一个Feign包,里面写被调用方对应的接口。注意需要使用@FeignClient来标识被调用方是哪个微服务。 

    需要确保被调用方存在上述/dept/list等方法

     

    在调用方的启动类上添加注解扫描

    启动项目,客户端的代码风格和正常的Restful风格无异,相比Ribbon代码更清晰易懂了。

    同时也可以在ConfigBean类中配置负载均衡策略,同样实现了负载均衡~

    展开全文
  • 文章目录Spring Cloud Feign组件的重试策略及负载均衡策略简介Feign重试策略Feign负载均衡策略 Spring Cloud Feign组件的重试策略及负载均衡策略 简介 在使用Spring Cloud微服务框架的过程中,经常会使用Feign组件...
  • springcloud--Feign组件

    2020-08-30 16:16:25
    springcloud–Feign组件 Feign声明式服务调用 Feign 是一个声明式的 REST 客户端,它用了基于接口的注解方式,很方便实现客户端配置 Feign 最初由 Netflix 公司提供,但不支持SpringMVC注解,后由 SpringCloud 对其...
  • 我们的Feign组件就是解决这个问题滴! 二、Feign组件 1、简介 Feign是Netflflix开发的声明式,模板化的HTTP客户端,其灵感来自Retrofifit,JAXRS-2.0以及WebSocket. Feign可帮助我们更加便捷,优雅的调用...
  • SpringCloud-feign组件

    2020-03-26 21:19:19
    方面微服务之间的调用、访问 因为restTemplate使用虽然简单,但是在...SpringCloud提供了feign组件解决 用法类似于mybatis里面的mapper xml sqlsession.xxxList(“com.woniuxy.product.findById”,”1001”) map...
  • Feign是springcloud中至关重要的一个组件,负责各服务之间rest通信的传递...2 启动类中使用@enableFeign标签启用feign,这步搞定feign组件就已经引入了 3 定义一个接口,在接口中写入方法名 3 接口中最前使用@feignC...
  • springcloud是使用rest协议(RestTemplate)进行信息传递,同时在netfix的项目中实现了一个feign组件来简化编写代码的麻烦,并且有自动负载均衡 调用的原理: 通过动态代理,产生了一个代理类交给了spring容器。...
  • feign组件的功能与实现原理

    千次阅读 2019-05-17 21:12:21
    springcloud是使用rest协议进行信息传递,同时在netfix的项目中实现了一个feign组件来简化编写代码的麻烦 feign的使用方式如下 1 定义一个接口interface public interface helloclient(){ @RequestLine("GET /...
  • SpringCloud-Feign组件小坑 FeignClient接口如使用@PathVariable ,必须指定value属性 代码示例: @FeignClient("login-server") public interface UserFeignClient { @GetMapping(value = "/getInfo/{id}") ...
  • springboot 抽取feign组件作为jar包依赖注入失败 报错信息: *************************** APPLICATION FAILED TO START *************************** Description: Field yjFeign in sanyi.memberservice....
  • springCloud之Feign组件实战以及避坑指南 首先是Feign这边的调用,具体代码入下图所示 主要说下fallback,fallback主要是调用目标微服务失败后执行的方法如下图所示 注意!!!坑的地方来了,这样配置...
  • 关于SpringCloud的Feign组件的动态调用

    千次阅读 2020-09-25 23:04:50
    如果需要调用多个服务,那我们是不是就需要手动的配置多个,于是找了很多博客后,加上自己的实际实践,总结了feign组件的动态调用,可以方便我们的程序开发,省去很多不必要的代码,但由此可能会带来一些feign的性能...
  • springcloud微服务架构feign组件 是一个声明式的伪RPC的REST客户端,它用了基于接口的注解方式,很方便的客户端配置,刚开始使用时还不习惯,感觉是在客户端写服务端的代码,Spring Cloud 给 Feign 添加了支持Spring...
  • 文章目录SpringBoot集成Feign组件调用第三方接口一、 POM文件引入二、项目整体结构示意1、启动类2、yml 配置3、rmi模块代码4、Controller调用代码三、 一些说明 SpringBoot集成Feign组件调用第三方接口 一、 POM文件...
  • 当一个模块需要访问另外一个模块的数据的时候,由于两个模块相互独立,Feign组件就在其中起到了类似搭桥的作用,实现两个组件间的数据交互。 引入Feign依赖 例如Order模块需要Product模块的数据,在Order模块的Pom...
  • Spring Cloud 学习(三)负载均衡之Feign组件(F版) 上一篇文章,讲述了如何通过RestTemplate+Ribbon去消费服务,这篇文章主要讲述如何通过Feign去消费服务。 Feign简介 Feign是一个声明式的伪Http客户端,它...
  • SpringCloud03_Ribbon客户端负载均衡和Feign组件 Ribbon 基于HTTP和TCP的客户端负载均衡工具(默认轮询策略,默认超时时间1秒) 服务端负载均衡 负载均衡算法在服务端 由负载均衡器维护服务地址列表 客户端...
  • springcloud——Feign组件

    2020-12-17 17:31:16
    1.在消费端微服务导入Feign依赖 2.为需要调用的服务创建接口,在接口中添加注解和路径。Feign通过动态代理生成这个接口的实现类,调用远程服务返回结果。 3.在消费端启动上添加@EnableFeignClients,开启Feign功能...
  • Spring Cloud Feign组件

    2019-05-12 18:12:51
    Feign简介 Feign是一个声明式的Web服务客户端,使得它写Web服务变得简单。使用Feign,只需要创建一个接口并注解,它具有可插拔的注解特性。Feign基于Netflix Feign实现,整合了Spring Cloud Ribbon与Spring Cloud ...
  • Feign是在Ribbon的基础上进行了一次改进,Feign本身已经集成了Ribbon依赖和自动配置,因此我们不需要额外引入依赖,也不需要再注册RestTemplate对象。 Feign可以帮助我们更加便携、优雅的调用HTTP API 在Spring ...
  • 16、Feign组件进阶

    2020-03-25 14:53:36
    一、 Feign的配置 从Spring Cloud Edgware开始,Feign支持使用属性自定义Feign。对于一个指定名称的Feign Client(例如该Feign Client的名称为feignName ),Feign支持如下配置项: feign: client: config: ...
  • 我在利用SpringCloud进行微服务开发时,使用feign组件进行远程调用,结果产生了如下异常信息: Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name '...
  • 对于Feign组件的理解

    2021-05-21 23:45:47
    自己对于Feign理解如下: 使用feign这种声明式实现远程服务调用,即在commons服务中定义API接口即GoodsRemoteClient, 即该接口GoodsRemoteClient即为一个FeignClient,定义FeignClient时,还需要备注好该...
  • feign组件的了解

    2020-11-19 10:00:40
    https://blog.csdn.net/justry_deng/article/details/80785973?utm_source=blogxgwz7
  • Feign是spring cloud netflix组件中的一个轻量级RESTful的HTTP服务客户端,实现了负载均衡和Rest调用的开源框架,封装了Ribbon和RestTemplate,实现了面向接口编程。 Feign内置了Ribbon,用来做客户端的负载均衡调用...
  • 要使用Feign组件,只要在普通的基础服务(参考:SpringCloud-搭建微服务提供者-客户端-Client)上增加配置即可: 1.pom.xml文件增加配置: <!-- 引入 Feign, 可以以声明的方式调用微服务 --> <dependency&...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 18,734
精华内容 7,493
关键字:

feign组件