文章目录
零、前言
0. 之前写过两篇Spring Cloud,但是感觉不够具体,所以重新写了一份。
新 Spring Cloud (一) 之 Eureka 服务注册中心
新 SpringCloud (二) 之 Ribbon 负载均衡
新 Spring Cloud (三) 之 Hystrix熔断保护
新 Spring Cloud (四) 之 Fegin远程调用
新 Spring Cloud (五) 之 Zuul 网关
一、Fegin 简介
上回书说道,我们在项目中继承了Ribbon 实现了负载均衡,同时通过Hystrix 实现了熔断保护。看似完美,实则美中不足,在我们进行请求的时候,我们会写大量关于请求链接的地址。
如下 : 如果我们调用这个driver/takeOrder 100次,则我们需要重复写100次,如果我们需要调用其他的接口,则也要重复书写 restTemplate.postForObject("http://eureka-server-provider/xxxxx",multiValueMap,XXX.class);
这种类似的代码,麻烦且不说,而且易错。
String result = restTemplate.postForObject("http://eureka-server-provider/driver/takeOrder", multiValueMap, String.class); // 麻烦易错!!!!!
所以我们在这里继承Fegin,可以改变这个现状。那么什么是Fegin呢?
Feign是Nettix开发的声明式、模板化的HTTP客户端,其灵感来自Retroft、JAXRS-2.0
以及WebSocket。Feign 可帮助我们更加便捷、优雅地调用HTTP API。在Spring Cloud中,使用Feign非常简单一创建一 个接口, 并在接口上添加一些注解,代码就完成了。Feign 支持多种注解,例如Feign自带的注解或者JAX-RS注解等。Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
简而言之:
• Feign 采用的是基于接口的注解
• Feign 整合了ribbon
• Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样
二、项目搭建
1. 基础使用
这里的操作都是对服务消费者来说(EurekaServerConsumer)
-
首先我们需要引入对应依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
-
我们在启动类上加上 @EnableFeignClients 注解用于开启Fegin客户端。因为Fegin 内部自动集成了Ribbon负载均衡的RestTemplate,并且默认开启了负载均衡,所以我们不需要再注入RestTemplate。也不需要使用 @LoadBalanced 注解来开启负载均衡。
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients // 开启 Fegin客户端 public class EurekaServerConsumerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerConsumerApplication.class, args); } }
-
我们需要创建一个Fegin接口,来代理服务提供者的服务(EurekaServerProvider)。看似很高大上是吧,其实简单来说 Fegin就是对我们Ribbon的处理做了一个封装,让客户端实现了RPC调用。类似Dubbo中暴露远程服务的方式,区别在于Dubbo是基于私有二进制协议,而Feign本质上还是个HTTP客户端。
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; /** * @Data: 2019/10/25 * @Des: */ @FeignClient(value = "eureka-server-provider") // 标注该类是一个feign接口,其服务名是 eurake-server-provider @RequestMapping("driver") public interface DriverClient { /** * 司机接单服务 * @param msg * @return */ @RequestMapping("takeOrder") String takeOrder(@RequestParam("msg") String msg); }
- 首先这是一个接口,Feign会通过动态代理,帮我们生成实现类。这点跟mybatis的mapper很像
- @FeignClient,声明这是一个Feign客户端,类似@Mapper注解。同时通过value属性指定服务名称
- 接口中的定义方法,完全采用SpringMVC的注解,Feign会根据注解帮我们生成URL,并访问获取结果
-
改造原来接口的调用逻辑如下:
@Autowired private DriverClient driverClient ; // 注入Fegin接口 @RequestMapping("callTaxi") public String callTaxi(String msg) { // 通过Fegin接口访问服务消费者的服务 String result = driverClient.takeOrder(msg); System.out.println("乘客收到信息: " + result); return result; }
-
结束,调用可以,
2. Fegin 负载均衡
Fegin内部集成了Ribbon,并默认开启了负载均衡,所以对于负载均衡我们并不需要做什么处理了。
对于负载均衡策略的配置,和集成 Ribbon 的配置相同,可以通过yml配置或者通过注入Bean配置。
如果不需要配置负载均衡策略,我们就不需要做任何事。
3. Fegin 集成 Hystrix
Fegin内部也集成了Hystrix。但是默认是不开启, 所以我们需要通过配置开启他。
以下:所有的配置都在服务消费者(EurekaServerConsumer)中
- 在yml文件中开启 hystrix 熔断功能
feign:
hystrix:
enabled: true # 开启Fegin的熔断功能
-
我们在上一篇介绍Hystrix 的文章中将服务提供者的接口内容进行了修改,如下。改造之前的服务提供者服务(EurekaServerProvider),如下,不接待叫张三的人,目的是为了在伪造某种请求失败的状况来触发熔断。也就是说,这里如果请求参数是 张三,则请求失败,如果是其它,则请求成功。
1. 通过Fallback来进行熔断
-
在DriverClient 熔断类的
@FeignClient
注解指定熔断类为DriverClientFallBack
。注意,@RequestMapping一定不要写在类上面,在方法上拼接,否则会出现异常,提示DriverClient 注入了多个实例(找了一下午才找到的原因)@FeignClient(value = "eureka-server-provider", fallback = DriverClientFallBack.class) // 标注该类是一个feign接口,其服务名是 eurake-server-provider,fallback 指定熔断类 public interface DriverClient { /** * 司机接单服务 * @param msg * @return */ @RequestMapping("driver/takeOrder") String takeOrder(@RequestParam("msg") String msg); }
-
DriverClientFallBack 类是一个实现了 DriverClient 接口的类,并注入Spring容器中,如下。当调用driver/takeOrder 出现异常时,会进入 takeOrder 该熔断方法内。
@Component public class DriverClientFallBack implements DriverClient { @Override public String takeOrder(String msg) { return "DriverServiceFallBack 服务正忙,请稍后再试"; } }
-
调用结果如下,张三会走到熔断方法,其余参数正常调用:
2. 通过FallbackFactory来进行熔断
通过FallbackFactory 可以进行熔断,但是我们没有办法看到是为什么熔断,如果想看到异常信息,可以使用Fallback的增强版 FallbackFactory。
-
创建一个 DriverClientFallBackFactory 类 继承 FallbackFactory 类,
import feign.hystrix.FallbackFactory; import org.springframework.stereotype.Component; @Component public class DriverClientFallBackFactory implements FallbackFactory<DriverClient> { @Override public DriverClient create(Throwable throwable) { System.out.println("DriverServiceFallBackFactory " + throwable.getMessage()); return new DriverClient() { @Override public String takeOrder(String msg) { return "DriverServiceFallBackFactory 服务正忙,请稍后再试"; } }; } }
-
修改DriverClient 方法,使用fallbackFactory 指定熔断工厂类:
@FeignClient(value = "eureka-server-provider", fallbackFactory = DriverClientFallBackFactory.class) // 标注该类是一个feign接口,其服务名是 eurake-server-provider public interface DriverClient { /** * 司机接单服务 * @param msg * @return */ @RequestMapping("driver/takeOrder") String takeOrder(@RequestParam("msg") String msg); }
-
调用可以看到,错误信息。
3. Hystrix局部配置
一个服务中肯定会有多个Fegin客户端,而有的服务需要服务降级,有的不需要,这时就不能仅仅通过yml的全局配置来决定了。
比如滴滴平台上有多位注册司机,有的司机说,我不愿意接离跑太远的乘客,那么我们可以给他配置Hystrix熔断,超过一定“距离“ 熔断,有的司机愿意接远距离乘客,那么我们就没必要给他配置熔断(例子不太合适,方便理解一下而已)。
首先我们先来看一下@FeignClient 注解参数的意义:
参数 | 意义 |
---|---|
name | 指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现 |
decode404 | 当发生http 404错误时,如果该字段位true,会调用decoder进行解码,否则抛出FeignException |
url | url一般用于调试,可以手动指定@FeignClient调用的地址 |
configuration | Feign配置类,可以自定义Feign的Encoder、Decoder、LogLevel、Contract |
fallback | 定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口 |
fallbackFactory | 工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码 |
path | 定义当前FeignClient的统一前缀 |
-
编写配置类
@Configuration public class DriverConfiguration { /** * 配置日志级别 * - NONE:不记录任何日志信息,这是默认值。 * - BASIC:仅记录请求的方法,URL以及响应状态码和执行时间 * - HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息 * - FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。 * @return */ @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } /** * 配置不进行熔断 * @return */ @Bean public Feign.Builder feignBuilder() { return Feign.builder(); } }
-
指定配置类对应的FeginClient
-
再次访问,发现DriverClient已经关闭了Hystix 熔断。
以上:内容部分参考
https://www.cnblogs.com/shmilyToHu/p/10725944.html
https://blog.csdn.net/a15514920226/article/details/78924483
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正