热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

断路器Hystrix(Feign)

上一篇中我们讲了断路器Hystrix(Ribbon)本章讲解FeignHystrix已经Request请求传递,各种奇淫技巧….-Hyst

上一篇中我们讲了 断路器Hystrix(Ribbon) 本章讲解Feign+Hystrix已经Request请求传递,各种奇淫技巧….

- Hystrix

Hystrix支持回退概念:当 断路器 打开或运行错误时,执行默认的代码,给@FeignClient定义一个fallback属性,设置它实现回退的,还需要将您的实现类声明为Spring Bean。

官方文档:http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#spring-cloud-feign-hystrix-fallback

- 准备工作

1.启动Consul
2.创建 battcn-provider 和 battcn-consumer 如果看了上一章的,可以直接copy代码复用

- battcn-provider

- pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>

- ProviderApplication.java&#xff08;有变化&#xff09;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


&#64;SpringBootApplication
&#64;EnableDiscoveryClient
&#64;RestController
public class ProviderApplication {

&#64;Value("${spring.application.name}")
String applicationName;

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

&#64;GetMapping("/test1")
public String test1() {
return "My Name&#39;s :" &#43; applicationName &#43; " Email:1837307557&#64;qq.com";
}

&#64;GetMapping("/test2")
public String test2() {
System.out.println(1/0);
return "hello error";
}
}

- bootstrap.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14

server:
port: 8765

spring:
application:
name: battcn-provider
cloud:
consul:
host: localhost
port: 8500
enabled: true
discovery:
enabled: true
prefer-ip-address: true

- battcn-consumer

- pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-feignartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrixartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>

- ConsumerApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

&#64;SpringCloudApplication
&#64;EnableFeignClients//开启 FeignClient支持
public class ConsumerApplication {

&#64;Bean
&#64;LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}

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

}

- HiClient

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

package com.battcn.client;

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

/**
* &#64;author Levin
* &#64;date 2017-08-07.
*/
&#64;FeignClient(value &#61; "battcn-provider",fallback &#61; HiClient.HiClientFallback.class)
public interface HiClient {

&#64;GetMapping("/test1")
String test1();

&#64;GetMapping("/test2")
String test2();

&#64;Component
class HiClientFallback implements HiClient{
&#64;Override
public String test1() {
return "fallback....";
}

&#64;Override
public String test2() {
return "fallback...";
}
}
}

- HiController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

package com.battcn.controller;

import com.battcn.client.HiClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

&#64;RestController
public class HiController {
&#64;Autowired
HiClient hiClient;
&#64;GetMapping("/h1")
public String hi() {
return hiClient.test1();
}
&#64;GetMapping("/h2")
public String say() {
return hiClient.test2();
}
}

- bootstrap.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

server:
port: 8766

feign:
hystrix:
enabled: true #开启Feign Hystrix 支持

spring:
application:
name: battcn-consumer
cloud:
consul:
host: localhost
port: 8500
enabled: true
discovery:
enabled: true
prefer-ip-address: true

- 测试

启动&#xff1a;battcn-provider

启动&#xff1a;battcn-consumer

访问&#xff1a;http://localhost:8500/ 显示如下代表服务注册成功

查看注册中心查看注册中心

访问&#xff1a;http://localhost:8766/h1

1

My Name&#39;s :battcn-provider Email:1837307557&#64;qq.com #正确情况

访问&#xff1a;http://localhost:8766/h2

1

fallback... #错误情况&#xff0c;阻断输出fallback...

- 解锁新姿势

- 异常处理

画图工具&#xff1a;https://www.processon.com/

异常处理异常处理

如果我们FeignClient服务都是内部的&#xff0c;在客户端抛出异常直接往最外层抛出&#xff0c;就不需要在消费者通过硬编码处理了&#xff0c;关键代码&#xff08;完整代码看GIT&#xff09;…

battcn-provider 中异常处理

1
2
3
4
5
6
7
8
9
10
11

&#64;ExceptionHandler(value &#61; Exception.class)
&#64;ResponseBody
public ErrorResponseEntity jsonErrorHandler(Exception e, HttpServletResponse rep) throws Exception {
if (e instanceof BattcnException) {
BattcnException exception &#61; (BattcnException) e;
return exception.toErrorResponseEntity();
}
logger.error("服务器未知异常", e);
rep.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return new ErrorResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器未知异常");
}

battcn-consumer 中异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14

&#64;ExceptionHandler(value &#61; Exception.class)
&#64;ResponseBody
public ErrorResponseEntity jsonErrorHandler(Exception e, HttpServletResponse rep) throws Exception {
if (e instanceof HystrixBadRequestException) {
HystrixBadRequestException exception &#61; (HystrixBadRequestException) e;
rep.setStatus(HttpStatus.BAD_REQUEST.value());
logger.info("[HystrixBadRequestException] - [" &#43; exception.getMessage() &#43; "]");
JSONObject obj &#61; JSON.parseObject(exception.getMessage());
return new ErrorResponseEntity(obj.getInteger("customCode"), obj.getString("message"));
}
logger.error("服务器未知异常", e);
rep.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
return new ErrorResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器未知异常");
}

Hystrix中只有&#xff0c;HystrixBadRequestException 是不会被计数&#xff0c;也不会进入阻断器&#xff0c;所以我们定义一个自己的错误解码器

- FeignServiceErrorDecoder

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

package com.battcn.config;

import com.netflix.hystrix.exception.HystrixBadRequestException;
import feign.Response;
import feign.Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.IOException;

&#64;Component
public class FeignServiceErrorDecoder implements feign.codec.ErrorDecoder {
static Logger LOGGER &#61; LoggerFactory.getLogger(FeignServiceErrorDecoder.class);
&#64;Override
public Exception decode(String methodKey, Response response) {
try {
if (response.status() >&#61; 400 && response.status() <&#61; 499) {
String error &#61; Util.toString(response.body().asReader());
return new HystrixBadRequestException(error);
}
} catch (IOException e) {
LOGGER.error("[Feign解析异常] - [{}]", e);
}
return feign.FeignException.errorStatus(methodKey, response);
}
}

- 测试

访问&#xff1a;http://localhost:8766/h1

1

My Name&#39;s :battcn-provider Email:1837307557&#64;qq.com #正确情况

访问&#xff1a;http://localhost:8766/h2

1

{"customCode":400,"message":"请求错误"} #抛出异常&#xff0c;而不是进入阻断器

关闭battcn-provider&#xff1a;http://localhost:8766/h1

1

fallback... #服务down机&#xff0c;阻断输出fallback...

- Request 参数传递

在开发中难免会有 服务之间 请求头传递比如Token&#xff0c;ID&#xff0c;因为我们使用的是FeignClient 的方式&#xff0c;那么我们无法获得HttpServletRequest的上下文&#xff0c;这个时候怎么办呢&#xff1f;通过硬编码是比较low的一种&#xff0c;接下来为各位看官带来简单粗暴的&#xff08;也就知道这种&#xff0c;还有其它简单的方式欢迎交流….&#xff09;

参数传递参数传递

- FeignRequest&#xff08;consumer&#xff09;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

package com.battcn.config;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.UUID;

&#64;Component
public class FeignRequest implements RequestInterceptor {

final Logger LOGGER &#61; LoggerFactory.getLogger(this.getClass().getSimpleName());

&#64;Override
public void apply(RequestTemplate requestTemplate) {
//1.模拟获取request.header参数
String token &#61; UUID.randomUUID().toString().replace("-","").toUpperCase();
LOGGER.info("传递的Token - [{}]",token);
requestTemplate.header("token",token);//模拟将Token放入在 feign.Request对象中

}
}

- HelloController&#xff08;provider&#xff09;

1
2
3
4
5
6
7
8
9
10
11

&#64;Value("${spring.application.name}")
String applicationName;

&#64;Autowired
HttpServletRequest request;

&#64;Override
&#64;GetMapping("/test1")
public String test1() {
return "My Name&#39;s :" &#43; applicationName &#43; " Token:"&#43;request.getHeader("token");
}

- 测试

日志结果日志结果

结果&#xff1a;My Name&#39;s :battcn-provider Token:5588551D64C8478BA681A35892A03437 代表我们Token&#xff08;HttpServletRequest&#xff09;传递成功…

转:https://www.cnblogs.com/lywJ/p/10715572.html



推荐阅读
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
author-avatar
mobiledu2502862343
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有