SpringCloud学习笔记(四)—— 设置feign和ribbon

1、feign和ribbon介绍

Feign

Feign是一个声明式的web service客户端。(简化接口调用)

Ribbon

Ribbon是客户端负载均衡工具

 

2、环境搭建

由于feign集成了ribbon的方法,因此简单搭建时只需要一个openfeign依赖即可

 

2.1、pom添加依赖(基于消费者端项目)

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-openfeign</artifactId>

</dependency>

2.2、application.yml

server:
  port: 8200
spring:
  application:
    name: consumer-server
  profiles: dev
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:7001/eureka/
  instance:
    prefer-ip-address: true

feign:
  hystrix:
    enabled: true   #开启HYSTRIX,不然降级无法使用

2.2、远程服务调用接口(默认负载均衡算法:轮询)

package team.csrj.consumerserver.remote;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;


/**
 * 接口式定义api
 * fallbackFactory:定义降级处理的方法在哪
 * 
 * fallback只是重写了回退方法。
 * fallfactory层面比较深,因为它可以调出底层异常。
 */
@Component
@FeignClient(value = "producer-8001",fallbackFactory= ProducerRemoteHystrix.class)
public interface ProducerRemote {
    @GetMapping("/hello")
    String getPort();
}

2.3、远程服务降级类

package team.csrj.consumerserver.remote;

import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

@Component
public class ProducerRemoteHystrix implements FallbackFactory<ProducerRemote> {

    @Override
    public ProducerRemote create(Throwable throwable) {
        return new ProducerRemote(){
            @Override
            public String getPort() {
                return "该服务异常,请稍后重试";
            }
        };
    }
}

 2.4、controller

package team.csrj.consumerserver.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import team.csrj.consumerserver.remote.ProducerRemote;

@RestController
public class ConsumerController {
    @Autowired
    private ProducerRemote producerRemote;
    @RequestMapping("/hello")
    public String get(){
        return  producerRemote.getPort();
    }
}

2.5、程序入口

package team.csrj.consumerserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@EnableEurekaClient
@EnableFeignClients
@SpringBootApplication
public class ConsumerServerApplication {

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

2.6、后期修改负载均衡算法

只要在消费者端的application.yml中加入以下配置即可

producer-server:  #服务端的注册id
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #在此处输入需要的算法类

2.7、熔断到降级的流程解释

Hystrix提供了如下的几个关键参数,来对一个熔断器进行配置:

circuitBreaker.requestVolumeThreshold    //滑动窗口的大小,默认为20

circuitBreaker.sleepWindowInMilliseconds //过多长时间,熔断器再次检测是否开启,默认为5000,即5s钟

circuitBreaker.errorThresholdPercentage  //错误率,默认50%

3个参数放在一起,所表达的意思就是:

 

    每当20个请求中,有50%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到5s钟之后,重新检测该触发条件,判断是否把熔断器关闭,或者继续打开。

 

这里面有个很关键点,达到熔断之后,那么后面它就直接不去调该微服务。那么既然不去调该微服务或者调的时候出现异常,出现这种情况首先不可能直接把错误信息传给用户,所以针对熔断

 

我们可以考虑采取降级策略。所谓降级,就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值。

 

2.8、feign全局异常处理

@controllerAdvice或者HandlerExceptionResolver是不能直接捕获到FeignException,所以需要在Feign层面拿到具体异常重新封装。即消费者调用服务端时,服务端抛出异常,消费者端无法捕获,只能设置全局的feign异常处理才能接收服务端抛出的异常。

@Configuration
public class FeignExceptionConfig implements ErrorDecoder {

    @Override
    public Exception decode(String methodKey, Response response) {
        Integer status = null; // 错误状态码
        String message = null; // 错误信息
        try {
            switch (response.status()) {
                case 500:
                    if (response.body() != null) {
                        JSONObject body = JSONObject.fromObject(Util.toString(response.body().asReader()));
                        status = body.getInt("status");
                        message = body.getString("message");
                    }
                    break;
                }
        } catch (Exception e) {
            status = 500;
            message = "System is analysis body error";
            e.printStackTrace();
        }
        return new Exception(status, message);
    }
}

猜你喜欢

转载自blog.csdn.net/AlphonesEric/article/details/89047212