上一篇中我们讲了 断路器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)传递成功…
- 004声明式服务调用Feign & 断路器Hystrix
1.POM配置 和普通Spring Boot工程相比,添加了Eureka Client.Feign.Hystrix依赖和Spring Cloud依赖管理 <dependencies> &l ...
- SpringCloud学习系列之三----- 断路器(Hystrix)和断路器监控(Dashboard)
前言 本篇主要介绍的是SpringCloud中的断路器(Hystrix)和断路器指标看板(Dashboard)的相关使用知识. SpringCloud Hystrix Hystrix 介绍 Netfl ...
- 【Spring Cloud笔记】 断路器-hystrix
在微服务架构中,一个微服务的超时失败可能导致瀑布式连锁反映,Spring Cloud Netflix 的断路器Hystrix通过自主反馈,防止了这种情况发生.下面介绍简单的断路器使用方法. [step ...
- spring cloud学习(五)断路器 Hystrix
断路器 Hystrix 断路器模式 (云计算设计模式) 断路器模式源于Martin Fowler的Circuit Breaker一文. 在分布式环境中,其中的应用程序执行访问远程资源和服务的操作,有可 ...
- 【Spring Cloud学习之六】断路器-Hystrix
环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2 Spring Cloud 1.2 一.服务雪崩1.什么是服务雪崩分布式系统中经常会出现某个基础服务不可用造成整个系统不 ...
- Spring Cloud系列(四):断路器Hystrix
上一篇介绍了负载均衡的配置方法,做负载均衡是为了保证高可用性,但是有时候服务提供者挂掉了,比如服务A调用了服务B,服务B又调用了服务C,然后有一天服务C的所有节点都挂掉了,这时服务B就会因为C异常而在 ...
- SpringCloud IDEA 教学 (四) 断路器(Hystrix)
写在开始 在SpringCloud项目中,服务之间相互调用(RPC Remote Procedure Call —远程过程调用),处于调用链路底层的服务产生不可用情况时,请求会产生堆积使得服务器线程阻 ...
- 断路器Hystrix与Turbine集群监控-Spring Cloud学习第三天(非原创)
文章大纲 一.Hystrix基础介绍二.断路器Hystrix简单使用三.自定义Hystrix请求命令四.Hystrix的服务降级与异常处理五.Hystrix的请求缓存与请求合并六.Hystrix仪表盘 ...
- 断路器-Hystrix的深入了解
前言 高可用相关的技术以及架构,对于大型复杂的分布式系统,是非常重要的.而高可用架构中,非常重要的一个环节,就是如何将分布式系统中的各个服务打造成高可用的服务,从而足以应对分布式系统环境中的各种各样的 ...
随机推荐
- java实现字符串比较
标题:字符串比较 我们需要一个新的字符串比较函数compare(s1, s2). 对这个函数要求是: 1. 它返回一个整数,表示比较的结果. 2. 结果为正值,则前一个串大,为负值,后一个串大,否则, ...
- java实现第四届蓝桥杯快速排序
快速排序 题目描述 快速排序算法是典型的分治思想的运用.它使用某个key把全部元素分成两组,其中一组的元素不大于另一组.然后对这两组再次进行递归排序. 以下代码实现了快速排序.请仔细阅读代码,填写缺少 ...
- uniapp每隔几秒执行一下网络请求(h5端亲测可以,其他端未测试)
methods: { //执行网络请求 run() { uni.request({ method: 'GET',//请求方式 url: ‘’//请求地址 }).then(res=>{ conso ...
- python3 基本书写规范
一.缩进在类.函数定义完成后需要接着写子代码快需要在定义完成后加上: 缩进格式为首字母开始空格4个位置(取消了大括号以冒号代替子模块)例: class pop: #类的定义方式 def pip: #函 ...
- 手把手教你用JS/Vue/React实现幸运水果机(80后情怀之作)
项目体验地址 免费视频教程 分别使用原生JS,Vue和React,手把手教你开发一个H5小游戏,快速上手Vue和React框架的使用. 项目截图 在线体验 在线体验 游戏介绍 幸运水果机是一款街机游戏 ...
- 免费 IP 代理池示例
使用文档 import requests import re import random from concurrent.futures import ThreadPoolExecutor impor ...
- make & make install(make altinstall) 因动态库gcc版本问题
cc1: error: unrecognized command line option “-flot” 解决方式是:找到 configure之后的Makefile, 删除 -flot 原因是gcc ...
- MSSQL(DAC环境一下一些特殊的访问方式)
MSSQL(在DAC环境下访问: 存储过程) Server name: admin:计算机名\实例名 or admin:IP地址\实例名 ...
- pip安装报错: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy
pip安装报错 解决办法: pip install selenium -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
- Pikachu的暴力破解演示-----基于表单的暴力破解
1 首先打开XAMMP与burpsuite 2 打开游览器输入127.0.0.1:88进入pikachu,(由于我的端口有80改成88所以输入127.0.0.1:88要是没有更改80只需要输入127. ...