OpenFeign 简单使用


官方文档参考: https://docs.spring.io/spring-cloud-openfeign/docs/2.2.9.RELEASE/reference/html/,在 url 中选择自己对应的版本

github 文档参考:https://github.com/OpenFeign/feign

一、源码简单分析
1、导入依赖

导入依赖 OpenFeign 依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
2、自动导入类

spring-cloud-starter-openfeign 引入了 spring-cloud-openfeign-core 依赖,查看 spring-cloud-openfeign-core/META-INF/spring.factories 自动加载 FeignRibbonClientAutoConfiguration 类
在这里插入图片描述
查看 FeignRibbonClientAutoConfiguration 类默认加载 DefaultFeignLoadBalancedConfiguration
在这里插入图片描述

3、OkHttpFeignLoadBalancedConfiguration 类

OkHttpFeignLoadBalancedConfiguration 类中可以看到 @ConditionalOnClass(OkHttpClient.class) 注解,如果没有 OkHttpClient 类或者 feign.okhttp.enabled=false 则不加载 OkHttpFeignLoadBalancedConfiguration 类

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OkHttpClient.class)
@ConditionalOnProperty("feign.okhttp.enabled")
@Import(OkHttpFeignConfiguration.class)
class OkHttpFeignLoadBalancedConfiguration {

	@Bean
	@ConditionalOnMissingBean(Client.class)
	public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
			SpringClientFactory clientFactory, okhttp3.OkHttpClient okHttpClient) {
		OkHttpClient delegate = new OkHttpClient(okHttpClient);
		return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory);
	}
}
4、DefaultFeignLoadBalancedConfiguration 类

从 @ConditionalOnMissingBean 注解可以看到没有注入 Client 相关的 bean ,则注入该 client

@Configuration
class DefaultFeignLoadBalancedConfiguration {
    @Bean
    @ConditionalOnMissingBean
    public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory) {
        return new LoadBalancerFeignClient(new Client.Default(null, null),
                cachingFactory, clientFactory);
    }
}

查看 Client.Default 源码

    public static class Default implements Client {
        public Response execute(Request request, Options options) throws IOException {
            HttpURLConnection connection = this.convertAndSend(request, options);
            return this.convertResponse(connection, request);
        }

       HttpURLConnection convertAndSend(Request request, Options options) throws IOException{
            URL url = new URL(request.url());
            HttpURLConnection connection = this.getConnection(url);
       }
       public HttpURLConnection getConnection(URL url) throws IOException {
            return (HttpURLConnection)url.openConnection();
       }
}

从 Client.Default 源码可以看到每次请求都建立一个新的 HttpURLConnection 连接

其他 HttpClientFeignLoadBalancedConfiguration.class, OkHttpFeignLoadBalancedConfiguration.class, HttpClient5FeignLoadBalancedConfiguration.class 类似

5、小结

综上,默认情况下,spring cloud 没有引入 ApacheHttpClient 类(feign-httpclient jar包)和 okhhtp 类(okhttp jar包)和 ApacheHttp5Client ( ApacheHttp5Client jar 包) 类,所以默认使用 HttpURLConnection。

二 、OpenFeign 配置 Http 连接池

默认情况下,服务间调用使用 HttpURLConnection,效率比较低,可以通过连接池提高效率。

1、配置 Apache httpclient 连接池

pom.xml 中引入 feign-httpclient 依赖

        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>

bootstrap.yml 中添加配置

feign:
  httpclient:
    enabled: true
    hc5:
      enabled: false
  okhttp:
    enabled: false

简单配置如上即可,其他相关配置可使用默认值,详细配置可参考 FeignHttpClientProperties、FeignAutoConfiguration 类
在这里插入图片描述
HttpClient 默认配置如下,详细配置可参考 https://docs.spring.io/spring-cloud-openfeign/docs/2.2.9.RELEASE/reference/html/appendix.html

feign:
  httpclient:
    enabled: true
    hc5:
      enabled: false
    disable-ssl-validation: false # 禁用 SSL 验证
    max-connections: 200 # 最大连接
    max-connections-per-route: 50 # 路由最大连接数
    time-to-live: 900 # 连接存活时间
    time-to-live-unit: seconds # 连接存活时间单位
    follow-redirects: true # 重定向
    connection-timeout: 2000 # 连接超时
    connection-timer-repeat: 3000 # 连接重复间隔
  okhttp:
    enabled: false
2、配置 OkHttpClient 连接池

pom.xml 中引入 feign-okhttp 依赖

        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>

bootstrap.yml 中添加配置,其他详细配置参考上面的 Apache httpclient 连接池配置

feign:
  httpclient:
    enabled: false
    hc5:
      enabled: false
  okhttp:
    enabled: true
三、OpenFeign 简单测试
1、SPRING-CLOUD-SERVICE-OPENFEIGN 服务 bootstrap.yaml 配置
server:
  port: 20004
spring:
  application:
    name: SPRING-CLOUD-SERVICE-OPENFEIGN
  cloud:
    nacos:
      server-addr: 127.0.0.1:8848
      discovery:
        service: ${spring.application.name:DEFAULT-SERVICE-NAME}
        username: ${spring.cloud.nacos.username:nacos}
        password: ${spring.cloud.nacos.password:nacos}
        namespace: 2022-4-1-prod
        cluster-name: DEFAULT
feign:
  httpclient:
    enabled: true
2、调用测试
①、SPRING-CLOUD-SERVICE-CONFIG-PROVIDER 服务
@RestController
@RequestMapping("/config")
@RefreshScope
public class ConfigController {
   
    @Autowired
    private Student student;

    @GetMapping("/student")
    public String getStudent(HttpServletRequest request) {
        int port = request.getServerPort();
        String servletPath = request.getServletPath();
        String serverName = request.getServerName();
        String api = serverName + ":" + port + servletPath;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("API", api);
        jsonObject.put("student", student);
        return JSONObject.toJSONString(jsonObject);
    }
}

接口 http://192.168.159.1:20002/config/student
在这里插入图片描述

②、SPRING-CLOUD-SERVICE-OPENFEIGN 服务

启动类开启注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class SpringCloudStarterOpenfeignExamplesApplication {

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

新建 ProviderClient 服务接口

@Service
@FeignClient("SPRING-CLOUD-SERVICE-CONFIG-PROVIDER")
public interface ProviderClient {

    @GetMapping("/config/student")
    String selectService();
}

调用 SPRING-CLOUD-SERVICE-CONFIG-PROVIDER 服务

@RestController
@RequestMapping("/openfeign")
public class OpenFeignController {

    @Autowired
    private ProviderClient providerClient;
    @GetMapping("/select")
    public String selectService() {
        return providerClient.selectService();
    }
}

访问接口:http://127.0.0.1:20004/openfeign/select
在这里插入图片描述

3、使用 OpenFeign 接口注解

OpenFeign 默认支持 springmvc 默认注解(@GetMapping、@PostMapping、@Param、@RequestMapping)

如果要使用 OpenFeign 自带的如下接口注解
在这里插入图片描述
需要配置 feign 的合约模式,如果不配置就是用如上注解会报错 not annotated with HTTP method type (ex. GET, POST),注入如下 bean 即可

@Configuration
public class FeignConfiguration {
    //Contract feign的默认合约
    @Bean
    public Contract feignContract() {
        return new Contract.Default();
    }
}

SpringMVC 注解和 OpenFeign 不能共存

4、OpenFeign 配置优先级

如果我们同时创建 @Configuration @bean 和 yaml 配置文件配置,配置文件将覆盖 @Configuration值。
你可以将 feign.client.default-to-properties 改成 false,则 @Configuration 覆盖配置文件

5、OpenFeign GET 将 POJO 用作 GET 参数映射
①、服务提供者

控制层接口

@RestController
@RequestMapping("/discovery")
public class DiscoveryController {
    @GetMapping(value = "/pojo")
    public String selectPojo(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        JSONObject jsonObject = new JSONObject();
        for (String s : parameterMap.keySet()) {
            if (parameterMap.get(s).length == 1) {
                jsonObject.put(s, parameterMap.get(s)[0]);
            } else {
                jsonObject.put(s, parameterMap.get(s));
            }
        }
        return jsonObject.toJSONString();
    }
}

接口:http://127.0.0.1:20001/discovery/pojo?birthday=2022-02-22&username=admin&password=123456&address=西安
在这里插入图片描述

②、服务消费者

有的时候 GET 请求拼接 url 比较麻烦,则使用 @SpringQueryMap 注解将 POJO 对象用作 GET 参数映射

  • OpenFeign @QueryMap 注解支持将 POJO 用作 GET 参数映射。不幸的是,默认的 OpenFeign QueryMap 注解与 Spring 不兼容,因为它缺少value属性。
  • Spring Cloud OpenFeign 提供了等效的 @SpringQueryMap 注解,用于将 POJO 或 Map 参数注解为查询参数映射。

Feign 接口

@FeignClient(name = "SPRING-BOOT-SERVICE-DISCOVERY-CONSUMER")
@Service
public interface BootDiscoveryClient {

    @GetMapping(value = "/discovery/pojo")
    String selectPojo(@SpringQueryMap Map map);
}

控制层接口

@RestController
@RequestMapping("/openfeign")
public class OpenFeignController {
    @Autowired
    private BootDiscoveryClient bootDiscoveryClient;

    @GetMapping(value = "/pojo")
    public String selectPojo(@RequestBody Map map) {
        return bootDiscoveryClient.selectPojo(map);
    }
}

测试接口:http://127.0.0.1:20004/openfeign/pojo
在这里插入图片描述

@SpringQueryMap 注解将 pojo 参数拼接在 url 后面
http://SERVICE-NAME/discovery/pojo?birthday=2022-02-22&username=admin&password=123456&address=西安
之后根据负载均衡查找服务,将服务名替换成真实的地址去访问

6、OpenFeign GET 请求带 body

关于 get 请求传递 body 详细说明 https://zhuanlan.zhihu.com/p/456921996,简单说 get 请求不建议传递 body ,某些浏览器可能不支持

  • 支持 GET 请求 body: curl 、postman 、node.js 内置模块 http 、axios 、 Apache HttpClient 等
  • 不支持 GET 请求 body: HttpUrlConnection 、OkHttpClient

OpenFeign 有 Apache HttpClient 、OkHttp 、HttpUrlConnection 三种实现方式

HttpClient 支持 Get 请求传递 body,OkHttp 和 HttpUrlConnection 不支持,下面讲解 HttpClient 实现方式

①、Apache HttpClient 支持 Get 请求传递 body

服务提供者

@RestController
@RequestMapping("/discovery")
public class DiscoveryController {
    @GetMapping(value = "/json", consumes = MediaType.APPLICATION_JSON_VALUE)
    public String selectStudent(@RequestBody Student student) {
        return JSONObject.toJSONString(student);
    }
}

服务提供者接口:http://127.0.0.1:20001/discovery/json
在这里插入图片描述

服务消费者

控制层接口

@RestController
@RequestMapping("/openfeign")
public class OpenFeignController {

    @Autowired
    private BootDiscoveryClient bootDiscoveryClient;

    @GetMapping(value = "/json")
    public String selectStudent(@RequestBody Map map) {
        return bootDiscoveryClient.selectStudent(map);
    }
}

feign 接口

@FeignClient(name = "SPRING-BOOT-SERVICE-DISCOVERY-CONSUMER")
@Service
public interface BootDiscoveryClient {

    @GetMapping(value = "/discovery/json")
    String selectStudent(@RequestBody Map map);
}

服务消费者接口:http://127.0.0.1:20004/openfeign/json
在这里插入图片描述

②、OkHttpClient 不支持 Get 请求传递 body

查看 OkHttpClient 源码可以看到,如果 body 不为空,请求方式为 GET 或 HEAD 则抛出异常

    public static boolean permitsRequestBody(String method) {
        return !method.equals("GET") && !method.equals("HEAD");
    }
     public Request.Builder method(String method, @Nullable RequestBody body) {
            if (method == null) {
                throw new NullPointerException("method == null");
            } else if (method.length() == 0) {
                throw new IllegalArgumentException("method.length() == 0");
            } else if (body != null && !HttpMethod.permitsRequestBody(method)) {
                throw new IllegalArgumentException("method " + method + " must not have a request body.");
            } else if (body == null && HttpMethod.requiresRequestBody(method)) {
                throw new IllegalArgumentException("method " + method + " must have a request body.");
            } else {
                this.method = method;
                this.body = body;
                return this;
            }
        }
四、OpenFeign 负载均衡
1、OpenFeign 和 Feign 的区别
  • Feign 是 Spring Cloud 组件中一个轻量级 RESTful 的 HTTP 服务客户端
  • Feign 基于 ribbon 实现,可以理解为对 ribbon 的进一步封装
  • Feign 不是做负载均衡的,feign 只是集成了 ribbon,负载均衡还是 feign 内置的 ribbon 做。
  • Feign 的作用的替代 RestTemplate,性能比较低,但是可以使代码可读性很强。
  • OpenFeign 在 Feign 的基础上支持了 SpringMVC 的注解
2、默认负载均衡

从 BaseLoadBalancer 类可以看到, OpenFeign 负载均衡默认 RoundRobinRule 轮询方式

protected IRule rule = DEFAULT_RULE;
private final static IRule DEFAULT_RULE = new RoundRobinRule();
public Server chooseServer(Object key) {
        if (counter == null) {
            counter = createCounter();
        }
        counter.increment();
        if (rule == null) {
            return null;
        } else {
            try {
                return rule.choose(key);
            } catch (Exception e) {
                logger.warn("LoadBalancer [{}]:  Error choosing server for key {}", name, key, e);
                return null;
            }
        }
    }
3、简单测试

SPRING-CLOUD-SERVICE-CONFIG-PROVIDER 服务打成 jar,启动三个服务(如果是集群模式,要将服务放在云服务器,默认使用 内网 IP,不使用公网 IP,可以在启动时指定公网IP nohup java -Dfile.encoding=utf-8 -jar nacos-springcloud-config-examples-0.0.1-SNAPSHOT.jar --server.port=10002 --spring.cloud.nacos.discovery.ip=99.99.99.99 >> cloud.txt &

下面的适用于局域网服务注册

  • java -Dfile.encoding=utf-8 -jar nacos-springcloud-config-examples-0.0.1-SNAPSHOT.jar --server.port=10002
  • java -Dfile.encoding=utf-8 -jar nacos-springcloud-config-examples-0.0.1-SNAPSHOT.jar --server.port=20002
  • java -Dfile.encoding=utf-8 -jar nacos-springcloud-config-examples-0.0.1-SNAPSHOT.jar --server.port=30002

启动之后查看 nacos 服务控制台,可以看到 SPRING-CLOUD-SERVICE-CONFIG-PROVIDER 服务有三个实例
在这里插入图片描述
接口访问:http://127.0.0.1:20004/openfeign/select

如下可以看到默认负载均衡轮询 92.168.159.1:10001 92.168.159.1:10002 92.168.159.1:10003
在这里插入图片描述

4、解决错误

将项目打成 jar 包,读取 nacos 配置可能报错
org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1
在这里插入图片描述
报错原因: nacos 读取配置文件默认使用 UTF-8,通过 cmd 启动项目,项目默认编码格式为 GBK

解决方式 :添加启动参数-Dfile.encoding=utf-8
命令:java -Dfile.encoding=utf-8 -jar nacos-springcloud-config-examples-0.0.1-SNAPSHOT.jar --server.port=10002

五、自定义负载均衡

spring-cloud-ribbon 文档:https://docs.spring.io/spring-cloud-netflix/docs/2.2.9.RELEASE/reference/html/#spring-cloud-ribbon

1、IRule 负载均衡规则接口

IRule 负载均衡规则接口
在这里插入图片描述
负载均衡类说明

负载均衡实现策略
RandomRule随机
RoundRobinRule轮询
AvailabilityFilteringRule先过滤掉由于多次访问故障的服务,以及并 发连接数超过阈值的服务,然后对剩下的服 务按照轮询策略进行访问;
WeightedResponseTimeRule根据平均响应时间计算所有服务的权重,响应时间越快服务权重就越大被选中的概率即越高,如果服务刚启动时统计信息不足,则 使用RoundRobinRule策略,待统计信息足够会切换到该
RetryRule先按照RoundRobinRule策略分发如果分发 到的服务不能访问,则在指定时间内进行重试,然后分发其他可用的服务;
BestAvailableRule先过滤掉由于多次访问故障的服务,然后选 择一个并发量最小的服务;
ZoneAvoidanceRule (默认)综合判断服务节点所在区域的性能和服务节 点的可用性,来决定选择哪个服务;
2、Feign 代码配置负载均衡随机策略
①、@RibbonClient 不同服务配置不同的负载均衡

@RibbonClient 目的

  • @RibbonClient如果不添加,则当前项目调用的所有服务都是用该负载均衡策略
  • 如果当前项目有多个服务,可以指定每个服务的负载均衡策略
  • 自定义负载均衡配置类不能放在启动类包及其子包下,否则所有的服务共用一个策略,@RibbonClient 中的 name 将不起作用
  • @RibbonClient 注解可以把其他的配置类作为另外一个IOC容器导入到应用中,相当于加载了两个完全不相干的Spring的beans配置文件,此时应用中会有两个IOC容器。

项目结构,添加的两个负载均衡不在启动类同包以及扫描包下
在这里插入图片描述
负载均衡随机策略 MyRandomRule,自定义负载均衡算法 MyDiyRule 下面步骤 3

@Configuration
public class MyRandomRule {

    @Bean
    public IRule ribbonRule() {
        return new RandomRule(); // 采用随机策略
    }
}

@RibbonClient 不同服务配置不同策略,下面两个类随便添加进启动类或者子包下的类即可

@Configuration
@RibbonClient(name = "SPRING-BOOT-SERVICE-DISCOVERY-CONSUMER", configuration = MyDiyRule.class)
class MyDiyRuleConfigRibbonClient {
}

@Configuration
@RibbonClient(name = "SPRING-CLOUD-SERVICE-CONFIG-PROVIDER", configuration = MyRandomRule.class)
class ConfigRibbonClient {
}
②、配置文件服务配置不同的负载均衡

在这里插入图片描述
bootstrap.yaml 添加负载均衡配置(MyDiyRule、MyRandomRule 和上面同一个类)

SPRING-BOOT-SERVICE-DISCOVERY-CONSUMER:
  ribbon:
    NFLoadBalancerRuleClassName: com.ribbon.MyDiyRule
SPRING-CLOUD-SERVICE-CONFIG-PROVIDER:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
    # 上面的是 netflix 自带的随机算法,或者使用下面的是自定义的随机策略
    # NFLoadBalancerRuleClassName: com.ribbon.MyRandomRule
③、测试

SPRING-CLOUD-SERVICE-CONFIG-PROVIDER 服务随机策略:http://127.0.0.1:20004/openfeign/select
SPRING-BOOT-SERVICE-DISCOVERY-CONSUMER 自定义负载均衡策略:http://127.0.0.1:20004/openfeign/rule
在这里插入图片描述

3、自定义算法实现负载均衡

仿照 IRule 的接口实现类轮询策略 RoundRobinRule,实现自定义算法负载均衡,保证每个服务访问 3 次,切换其他服务

public class MyRule extends AbstractLoadBalancerRule {
    private int total;
    private int currentIndex;

    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        }
        Server server = null;

        while (server == null) {
            if (Thread.interrupted()) {
                return null;
            }
            // 获取运行中的服务
            List<Server> upList = lb.getReachableServers();
            // 获取所有服务
            List<Server> allList = lb.getAllServers();

            int serverCount = allList.size();
            if (serverCount == 0) {
                return null;
            }
            // 简单的判断,保证每个服务执行 5 次
            if (total % 3 == 0) {
                if (currentIndex < upList.size()-1) {
                    currentIndex++;
                } else {
                    currentIndex = 0;
                    this.total = 0;
                }
            }
            total++;
            // 从活着的服务中获取
            server = upList.get(currentIndex);
            if (server == null) {
                Thread.yield();
                continue;
            }

            if (server.isAlive()) {
                return (server);
            }
            server = null;
            Thread.yield();
        }
        return server;
    }

    @Override
    public Server choose(Object key) {
        return choose(getLoadBalancer(), key);
    }

    @Override
    public void initWithNiwsConfig(IClientConfig clientConfig) {}
}

测试自定义负载均衡策略
在这里插入图片描述

六、熔断降级控制组件

OpenFeign 默认引入了 Hystrix 服务控制组件

Hystrix 和 Sentinel 都是分布式服务架构中服务熔断降级控制组件,Sentinel 和 Hystrix 对比选型可参考

Hystrix 概念简单实用参考:https://blog.csdn.net/qq_38149225/article/details/109454418
Sentinel 使用参考:https://github.com/alibaba/Sentinel/wiki/如何使用

1、服务雪崩

分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。
在这里插入图片描述
如果由于流量激增,线程数有限,会导致访问超时,最终导致 C 服务失请求败,则 B 服务也会失败,最终导致 A 服务失败。

简单说:一个服务失败,导致整条链路的服务都失败的,我们称之为服务雪崩。

2、引起雪崩的原因和服务雪崩的三个阶段

原因大致有四:

  • 1、硬件故障;
  • 2、程序Bug;
  • 3、缓存击穿(用户大量访问缓存中没有的键值,导致大量请求查询数据库,使数据库压力过大);
  • 4、用户大量请求;

服务雪崩三个阶段:

  • 第一阶段: 服务不可用;
  • 第二阶段:调用端重试加大流量(用户重试/代码逻辑重试);
  • 第三阶段:服务调用者不可用(同步等待造成的资源耗尽);
3、雪崩解决方法

服务熔断:在一定时间内一定请求某个服务响应超时,则停止访问
服务降级:当某个服务熔断之后,服务将不再被调用,此时客户端可以自己准备一个本地的fallback(回退)回调,返回响应一个缺省值。 例如:(备用接口/缓存/MySQL/mock数据) 。这样做,虽然服务水平下降,但好歹可用,比直接挂掉要强,当然这也要看适合的业务场景。

七、hystrix 服务降级简单测试

openfeign hystrix 参考:https://docs.spring.io/spring-cloud-openfeign/docs/2.2.9.RELEASE/reference/html/#creating-feign-clients-manually
netflix hystrix 参考:https://docs.spring.io/spring-cloud-netflix/docs/2.2.9.RELEASE/reference/html/#circuit-breaker-hystrix-clients

1、服务消费者

pom.xml 核心依赖如下,openfeign 包含 hystrix

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

bootstrap.yaml 启用 hystrix 断路器,Feign 将使用断路器包装所有方法

  • Feign 开启 hystrix 断路器feign.hystrix.enabled=true
  • Feign 关闭 spring cloud 断路器 feign.circuitbreaker.enabled=true
feign:
  hystrix:
    enabled: true
  circuitbreaker:
    enabled: false

注意:启动类不能添加 @EnableCircuitBreaker ,如果添加该注解需要导入 spring-cloud-starter-netflix-hystrix 依赖

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
//@EnableCircuitBreaker
public class SpringCloudStarterOpenfeignExamplesApplication {

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

BootDiscoveryClient.java

@FeignClient(name = "SPRING-BOOT-SERVICE-DISCOVERY-CONSUMER",fallback = BootFallbackService.class)
@Service
public interface BootDiscoveryClient {
    @GetMapping(value = "/hystrix/calculate")
    String serviceDown(@SpringQueryMap Map map);
}

BootFallbackService.java 当请求超时错误回退类,需要声明为 spring bean,注意不能使用 @Controller 相关注解

@Component
public class BootFallbackService implements BootDiscoveryClient {
    @Override
    public String serviceDown(Map map) {
        return "serviceDown  方法请求获取数据超时或错误,进行了服务降级操作";
    }
}

服务消费者接口

@RestController
@RequestMapping("/hystrix")
public class HystrixController {
    @Autowired
    private BootDiscoveryClient bootDiscoveryClient;
    @GetMapping(value = "/calculate")
    public String serviceDown(String a,String b,String type) {
        Map<String,String> map = new HashMap<>();
        map.put("a",a); map.put("b",b); map.put("type",type);
        return bootDiscoveryClient.serviceDown(map);
    }
}

⭐⭐⭐⭐⭐⭐ 访问回退原因 ⭐⭐⭐⭐⭐⭐

FeignClient 接口

@Service
@FeignClient(value = "SPRING-CLOUD-SERVICE-CONFIG-PROVIDER",fallbackFactory = HystrixClientFallbackFactory.class)
public interface CloudConfigClient {

    @GetMapping("/config/student")
    String selectService();
}

HystrixClientFallbackFactory 回退类

@Component
public class HystrixClientFallbackFactory implements FallbackFactory<CloudConfigClient> {
    @Override
    public CloudConfigClient create(Throwable throwable) {
        return new CloudConfigClient() {

            @Override
            public String selectService() {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("message", "selectPojo  方法请求获取数据超时或错误,进行了服务降级操作");
                jsonObject.put("code", 444);
                jsonObject.put("err", throwable.getMessage());
                return jsonObject.toJSONString();
            }
        };
    }
}

测试 :http://127.0.0.1:20004/openfeign/select

服务提供者 debug,会导致读取超时,测试服务降级获取接口访问失败回退原因

在这里插入图片描述

2、服务提供者

服务提供者接口, @ApiAnnotation 为自定义注解,目的返回结果封装 url

    @GetMapping("/calculate")
    @ApiAnnotation
    public String calculate(String a, String b, String type) {
        int result = 0;
        int num1 = Integer.parseInt(a);
        int num2 = Integer.parseInt(b);
        switch (type) {
            case "+": result = num1 + num2; break;
            case "-": result = num1 - num2; break;
            case "*": result = num1 * num2; break;
            case "/": result = num1 / num2;  break;
        }
        return String.valueOf(result);
    }
3、测试

测试可以在服务提供者打断点模拟读取超时或者 10/0 抛一个算术异常

接口:http://127.0.0.1:20004/hystrix/calculate?a=10&b=0&type=/
在这里插入图片描述

4、Hystrix 断路器监控

Spring Cloud 断路器监控(Hystrix Dashboard)

八、Sentinel 简单测试

参考我的另一篇博客:https://blog.csdn.net/qq_41538097/article/details/124330640

使用OpenFeign,首先需要创建一个启动类,将其标记为@SpringBootApplication,并在注解中排除掉DataSource自动配置,同时添加@EnableFeignClients、@EnableEurekaClient和@EnableDiscoveryClient注解来启用Feign客户端和服务注册与发现功能。 接下来,需要定义一个接口,并使用@FeignClient注解来标识该接口是一个Feign客户端,并指定要调用的服务。在接口中,可以使用REST风格的方式来定义接口请求服务的方法。例如,可以使用@RequestMapping注解来指定请求路径和请求方法,然后在方法中返回要调用的服务的响应结果。 要在项目中使用OpenFeign,需要添加OpenFeign的依赖。可以在项目的pom.xml文件中添加以下依赖: ``` <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> <version>2.2.2.RELEASE</version> </dependency> ``` 最后,需要配置Feign接口的错误回滚配置。这可以通过在Feign接口上添加注解来实现。 综上所述,使用OpenFeign的步骤如下: 1. 创建一个启动类,并标记为@SpringBootApplication,同时排除DataSource自动配置,添加@EnableFeignClients、@EnableEurekaClient和@EnableDiscoveryClient注解。 2. 定义一个接口,并使用@FeignClient注解来标识该接口是一个Feign客户端,指定要调用的服务。 3. 在接口中使用REST风格的方式定义接口请求服务的方法,并添加相应的注解来配置请求路径和请求方法。 4. 添加OpenFeign的依赖到项目的pom.xml文件中。 5. 配置Feign接口的错误回滚配置,可以通过在接口上添加注解来实现。 请注意,确保在项目中正确配置了服务注册中心和相应的服务提供者。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [OpenFeign的理解和使用](https://blog.csdn.net/m0_45016797/article/details/123633386)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [OpenFeign简单使用](https://blog.csdn.net/qq_50626505/article/details/124060848)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值