上一篇中我们讲了 断路器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.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

- ProviderApplication.java(有变化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class ProviderApplication { @Value("${spring.application.name}")
String applicationName; public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
} @GetMapping("/test1")
public String test1() {
return "My Name's :" + applicationName + " Email:1837307557@qq.com";
} @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.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

- ConsumerApplication

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@SpringCloudApplication
@EnableFeignClients//开启 FeignClient支持
public class ConsumerApplication { @Bean
@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; /**
* @author Levin
* @date 2017-08-07.
*/
@FeignClient(value = "battcn-provider",fallback = HiClient.HiClientFallback.class)
public interface HiClient { @GetMapping("/test1")
String test1(); @GetMapping("/test2")
String test2(); @Component
class HiClientFallback implements HiClient{
@Override
public String test1() {
return "fallback....";
} @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; @RestController
public class HiController {
@Autowired
HiClient hiClient;
@GetMapping("/h1")
public String hi() {
return hiClient.test1();
}
@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

- 测试

启动:battcn-provider

启动:battcn-consumer

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

查看注册中心

访问:http://localhost:8766/h1

1
My Name's :battcn-provider Email:1837307557@qq.com	#正确情况

访问:http://localhost:8766/h2

1
fallback...  	#错误情况,阻断输出fallback...

- 解锁新姿势

- 异常处理

画图工具:https://www.processon.com/

异常处理

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

battcn-provider 中异常处理

1
2
3
4
5
6
7
8
9
10
11
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ErrorResponseEntity jsonErrorHandler(Exception e, HttpServletResponse rep) throws Exception {
if (e instanceof BattcnException) {
BattcnException exception = (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
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ErrorResponseEntity jsonErrorHandler(Exception e, HttpServletResponse rep) throws Exception {
if (e instanceof HystrixBadRequestException) {
HystrixBadRequestException exception = (HystrixBadRequestException) e;
rep.setStatus(HttpStatus.BAD_REQUEST.value());
logger.info("[HystrixBadRequestException] - [" + exception.getMessage() + "]");
JSONObject obj = 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中只有,HystrixBadRequestException 是不会被计数,也不会进入阻断器,所以我们定义一个自己的错误解码器

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

- 测试

访问:http://localhost:8766/h1

1
My Name's :battcn-provider Email:1837307557@qq.com	#正确情况

访问:http://localhost:8766/h2

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

关闭battcn-provider:http://localhost:8766/h1

1
fallback...  	#服务down机,阻断输出fallback...

- Request 参数传递

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

参数传递

- FeignRequest(consumer)

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; @Component
public class FeignRequest implements RequestInterceptor { final Logger LOGGER = LoggerFactory.getLogger(this.getClass().getSimpleName()); @Override
public void apply(RequestTemplate requestTemplate) {
//1.模拟获取request.header参数
String token = UUID.randomUUID().toString().replace("-","").toUpperCase();
LOGGER.info("传递的Token - [{}]",token);
requestTemplate.header("token",token);//模拟将Token放入在 feign.Request对象中 }
}

- HelloController(provider)

1
2
3
4
5
6
7
8
9
10
11
@Value("${spring.application.name}")
String applicationName; @Autowired
HttpServletRequest request; @Override
@GetMapping("/test1")
public String test1() {
return "My Name's :" + applicationName + " Token:"+request.getHeader("token");
}

- 测试

日志结果

结果:My Name's :battcn-provider Token:5588551D64C8478BA681A35892A03437 代表我们Token(HttpServletRequest)传递成功…

断路器Hystrix(Feign)的更多相关文章

  1. 004声明式服务调用Feign & 断路器Hystrix

    1.POM配置 和普通Spring Boot工程相比,添加了Eureka Client.Feign.Hystrix依赖和Spring Cloud依赖管理 <dependencies> &l ...

  2. SpringCloud学习系列之三----- 断路器(Hystrix)和断路器监控(Dashboard)

    前言 本篇主要介绍的是SpringCloud中的断路器(Hystrix)和断路器指标看板(Dashboard)的相关使用知识. SpringCloud Hystrix Hystrix 介绍 Netfl ...

  3. 【Spring Cloud笔记】 断路器-hystrix

    在微服务架构中,一个微服务的超时失败可能导致瀑布式连锁反映,Spring Cloud Netflix 的断路器Hystrix通过自主反馈,防止了这种情况发生.下面介绍简单的断路器使用方法. [step ...

  4. spring cloud学习(五)断路器 Hystrix

    断路器 Hystrix 断路器模式 (云计算设计模式) 断路器模式源于Martin Fowler的Circuit Breaker一文. 在分布式环境中,其中的应用程序执行访问远程资源和服务的操作,有可 ...

  5. 【Spring Cloud学习之六】断路器-Hystrix

    环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 Spring Cloud 1.2 一.服务雪崩1.什么是服务雪崩分布式系统中经常会出现某个基础服务不可用造成整个系统不 ...

  6. Spring Cloud系列(四):断路器Hystrix

    上一篇介绍了负载均衡的配置方法,做负载均衡是为了保证高可用性,但是有时候服务提供者挂掉了,比如服务A调用了服务B,服务B又调用了服务C,然后有一天服务C的所有节点都挂掉了,这时服务B就会因为C异常而在 ...

  7. SpringCloud IDEA 教学 (四) 断路器(Hystrix)

    写在开始 在SpringCloud项目中,服务之间相互调用(RPC Remote Procedure Call —远程过程调用),处于调用链路底层的服务产生不可用情况时,请求会产生堆积使得服务器线程阻 ...

  8. 断路器Hystrix与Turbine集群监控-Spring Cloud学习第三天(非原创)

    文章大纲 一.Hystrix基础介绍二.断路器Hystrix简单使用三.自定义Hystrix请求命令四.Hystrix的服务降级与异常处理五.Hystrix的请求缓存与请求合并六.Hystrix仪表盘 ...

  9. 断路器-Hystrix的深入了解

    前言 高可用相关的技术以及架构,对于大型复杂的分布式系统,是非常重要的.而高可用架构中,非常重要的一个环节,就是如何将分布式系统中的各个服务打造成高可用的服务,从而足以应对分布式系统环境中的各种各样的 ...

随机推荐

  1. Java实现 蓝桥杯 算法训练 最小乘积

    算法训练 最小乘积(基本型) 时间限制:1.0s 内存限制:512.0MB 问题描述 给两组数,各n个. 请调整每组数的排列顺序,使得两组数据相同下标元素对应相乘,然后相加的和最小.要求程序输出这个最 ...

  2. Java中map.getOrDefault()方法的使用

    Map.getOrDefault(Object key, V defaultValue)方法的作用是:   当Map集合中有这个key时,就使用这个key值:   如果没有就使用默认值defaultV ...

  3. java实现第六届蓝桥杯居民集会

    居民集会 蓝桥村的居民都生活在一条公路的边上,公路的长度为L,每户家庭的位置都用这户家庭到公路的起点的距离来计算,第i户家庭距起点的距离为di. 每年,蓝桥村都要举行一次集会.今年,由于村里的人口太多 ...

  4. 【CSS】电脑、移动端公用样式

    电脑端: /* Public */ @charset "utf-8"; html, body, div, p, ul, ol, li, dl, dt, dd, h1, h2, h3 ...

  5. jquery 手写一个简单浮窗的反面教材

    前言 初学jquery写的代码,陈年往事回忆一下. 正文 介绍一下大体思路 思路: 1.需要控制一块区域,这块区域一开始是隐藏的. 2.这个区域需要关闭按钮,同时我需要写绑定事件,关闭的时候让这块区域 ...

  6. 不需重新编译php,安装postgresql扩展(pgsql和pdo_pgsql)

    为了不重新编译php,使用phpize工具进行追加. 1.下载phpX安装包 访问php官方下载页,找到自己对应的php版本:https://secure.php.net/downloads.php ...

  7. Hunter’s Apprentice(判断所走路线为顺时针或逆时针)【Green公式】

    Hunter's Apprentice 题目链接(点击) 题目描述 When you were five years old, you watched in horror as a spiked de ...

  8. 在Centos7中,从主机 Windows 上无法远程访问 Linux 上rabbitmq的解决方法

    当在 Linux 上配置好 Rabbitmq服务器后,如果从主机中无法访问到 Linux 中的Rabbitmq服务器时,需要做如下的检查: 1. Rabbitmq是否启动成功 在控制台输入: ps - ...

  9. (一)maven搭建和idea的配置

    一.下载安装 前往 https://maven.apache.org/download.cgi 下载最新版的Maven程序.解压到任意目录 (要养成不起中文路径的好习惯,否则有时间出问题真的很难找) ...

  10. Android笔记布局资源文件

    在项目的res--layout目录下的文件叫布局资源文件,用于控制页面的布局显示 在Java代码中引用布局资源我们已经很熟悉了. setContentView(R.layout.activity_ma ...