一起来学SpringCloud之
来源:互联网 发布:linux lamp一键安装 编辑:程序博客网 时间:2024/05/16 01:56
上一篇中我们讲了 断路器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
<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(有变化)
@SpringBootApplication@EnableDiscoveryClient@RestControllerpublic 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
server: port: 8765spring: application: name: battcn-provider cloud: consul: host: localhost port: 8500 enabled: true discovery: enabled: true prefer-ip-address: true
- battcn-consumer
- pom.xml
<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
@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
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
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;@RestControllerpublic class HiController { @Autowired HiClient hiClient; @GetMapping("/h1") public String hi() { return hiClient.test1(); } @GetMapping("/h2") public String say() { return hiClient.test2(); }}
- bootstrap.yml
server: port: 8766feign: 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
My Name's :battcn-provider Email:1837307557@qq.com #正确情况
访问:http://localhost:8766/h2
fallback... #错误情况,阻断输出fallback...
- 解锁新姿势
- 异常处理
画图工具:https://www.processon.com/
如果我们
FeignClient
服务都是内部的,在客户端抛出异常直接往最外层抛出,就不需要在消费者通过硬编码处理了,关键代码(完整代码看GIT)…
battcn-provider
中异常处理
@ExceptionHandler(value = Exception.class)@ResponseBodypublic 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
中异常处理
@ExceptionHandler(value = Exception.class)@ResponseBodypublic 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
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;@Componentpublic 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
My Name's :battcn-provider Email:1837307557@qq.com #正确情况
访问:http://localhost:8766/h2
{"customCode":400,"message":"请求错误"} #抛出异常,而不是进入阻断器
关闭battcn-provider:http://localhost:8766/h1
fallback... #服务down机,阻断输出fallback...
- Request 参数传递
在开发中难免会有 服务之间 请求头传递比如Token,ID,因为我们使用的是
FeignClient
的方式,那么我们无法获得HttpServletRequest
的上下文,这个时候怎么办呢?通过硬编码是比较low
的一种,接下来为各位看官带来简单粗暴的(也就知道这种,还有其它简单的方式欢迎交流….)
- FeignRequest(consumer)
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;@Componentpublic 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)
@Value("${spring.application.name}")String applicationName;@AutowiredHttpServletRequest 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)传递成功…
- 说点什么
画图工具:https://www.processon.com/
本章代码(battcn-provider/consumer):https://git.oschina.net/battcn/battcn-cloud/tree/master/battcn-cloud-hystrix-feign
如有问题请及时与我联系
- 个人QQ:1837307557
- Spring Cloud中国社区①:415028731
- Spring For All 社区⑤:157525002
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学SpringCloud之
- 一起来学css之选择器
- 一起来学反汇编-之if语句
- 一起来学反汇编-之switch语句
- 一起来学反汇编之循环语句
- 一起来学POSIX thread 之 基本概念
- 一起来学POSIX thread 之 线程状态
- 继承关系中子类与父类加载与初始化
- 回顾大一·C语言编程4.1(1)
- 如何通过dba_hist_active_sess_history分析数据库历史性能问题
- 编码规范
- CS R20 C(贪心+二分) D(套路(n后第k个合法数)二分+数位DP.) E(好题:回文,字符串哈希)
- 一起来学SpringCloud之
- ajax读取本地json文件
- C++对结构体元素排序
- 计算机网络基础知识总结
- spring bean 基于xml的4中初始化方法
- jQuery中each的用法之退出循环和结束本次循环
- 一起来学SpringCloud之
- Memcache 分布式高可用集群介绍
- android Studio