1 Feign的使用

案例接着 Hystrix案例

在前面的学习中,我们使用了Ribbon的负载均衡功能,大大简化了远程调用时的代码:

String baseUrl = "http://user-service/user/";
User user = this.restTemplate.getForObject(baseUrl + id, User.class)

需要4点:提供服务的地址http://user-service/user/ ,参数id,请求方式get,返回类型User

如果就学到这里,你可能以后需要编写类似的大量重复代码,格式基本相同,无非参数不一样。有没有更优雅的方式,来对这些代码再次优化呢?这就是我们接下来要学的Feign的功能了。
Feign可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样。你不用再自己拼接url,拼接参数等等操作,一切都交给Feign去做。

在服务调用者user-consumer中操作

1)添加依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency>

2)修改启动类

@EnableFeignClients //开启feign功能
@SpringCloudApplication  //点进去看看,抵三个注解
public class ConsumerApplicationStarter {public static void main(String[] args) {SpringApplication.run(ConsumerApplicationStarter.class);}
}

3)编写UserClient接口

//去eureka拉取服务,使用负载均衡来挑选
//支持hystrix,但是默认是关闭的   写法比较麻烦可以不使用
@FeignClient("user-service")
public interface UserClient {@GetMapping("user/{id}")User findUserById(@PathVariable("id") Long id);
}

这与上面的四点刚好相对应

  • 首先这是一个接口,Feign会通过动态代理,帮我们生成实现类。这点跟mybatis的mapper很像
  • @FeignClient,声明这是一个Feign客户端,类似@Mapper注解。同时通过value属性指定服务名称
  • 接口中的定义方法,完全采用SpringMVC的注解,Feign会根据注解帮我们生成URL,并访问获取结果

4)修改ConsumerController

@RestController
@RequestMapping("consumer")
public class ConsumerController {@Autowiredprivate UserClient userClient;@GetMapping("{id}")public User queryById(@PathVariable("id") Long id) {return userClient.findUserById(id);}
}

RestTemplate的注册被我删除了。Feign中已经自动集成了Ribbon负载均衡,因此我们不需要自己定义RestTemplate了

补充: Feign默认也有对Hystix的集成,只不过,默认情况下是关闭的。我们需要通过下面的参数来开启:

feign:hystrix:enabled: true  #feign  开启熔断 默认关闭
ribbon:ConnectionTimeout: 500 #Feign的负载均衡时长   抛出异常ReadTimeout: 2000 #超过两秒没读取到数据  抛出异常

配置会比较麻烦,先要修改UserClient,添加fallBack属性

@FeignClient(value = "user-service",fallback = UserClientFallback.class)
public interface UserClient {@GetMapping("user/{id}")User findUserById(@PathVariable("id") Long id);
}

添加UserClient 的实现类,实现findUserById方法

@Component
public class UserClientFallback implements UserClient {@Overridepublic User findUserById(Long id) {User user = new User();user.setUsername("用户未知");return user;}
}

既然能自己写Hystrix那就可以不使用Feign的Hystrix了。

主要功能还是简化远程调用,其他的小功能不再赘述。

2 网关Zuul

2.1 Zuul的功能介绍

服务网关是微服务架构中一个不可或缺的部分。通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由、均衡负载功能之外,它还具备了权限控制等功能。Spring Cloud Netflix中的Zuul就担任了这样的一个角色,为微服务架构提供了前门保护的作用,同时将权限控制这些较重的非业务逻辑内容迁移到服务路由层面,使得服务集群主体能够具备更高的可复用性和可测试性。

Zuul的官网

2.2 加入Zuul后的架构

不管是来自于客户端(PC或移动端)的请求,还是服务内部调用。一切对服务的请求都会经过Zuul这个网关,然后再由网关来实现 鉴权、动态路由等等操作。Zuul就是我们服务的统一入口。

从图中能够看出Zuul具有的功能有,最基本的路由,权限校验,负载均衡,下面将一一来介绍与使用。

2.3 Zuul快速入门

创建gateway模块

1)添加依赖 pom.xml内容如下

<parent><artifactId>spring-cloud-demo</artifactId><groupId>com.scu</groupId><version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion><artifactId>gateway</artifactId>
<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-zuul</artifactId></dependency>
</dependencies>

2)创建启动类

@SpringBootApplication
@EnableZuulProxy  //启用zuul
public class ZuulApplication {public static void main(String[] args) {SpringApplication.run(ZuulApplication.class);}
}

3)添加配置文件 application.yml

server:port: 10086   #端口号
spring:application:name: gateway  #服务名称
zuul:routes:xixi:  #路径id  随意写path: /user-service/**   #映射路径url: http://127.0.0.1:8083  #映射路径对应的url地址

启动项目后,当页面访问http://localhost:10086/user-service/user/1,之后路由地址为http://127.0.0.1:8083/user/1,即:将符合path 规则的一切请求,都代理到 url参数指定的地址,本例中,我们将 /user-service/**开头的请求,代理到http://127.0.0.1:8083

2.4 Zuul面向服务的路由

在刚才的路由规则中,我们把路径对应的服务地址写死了!如果同一服务有多个实例的话,这样做显然就不合理了。我们应该根据服务的名称,去Eureka注册中心查找 服务对应的所有实例列表,然后进行动态路由才对!

1)添加eureka依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency>

2)修改配置文件

server:port: 10086
spring:application:name: gateway
eureka:client:service-url:defaultZone: http://127.0.0.1:10001/eureka  #zuul也注册到eurekainstance:prefer-ip-address: trueip-address: 127.0.0.1
zuul:routes:xixi:path: /user-service/**serviceId: user-service   #服务提供方Id   zuul自动负载均衡

注意:似乎启动类上不加@EnableDiscoveryClient也行,但我还是加了,也不影响。

2.5 Zuul简化路由配置和默认配置

如果觉得上面写的麻烦, 那么可以进行简化,如下

zuul:routes: #服务id: 映射路径           默认配置也是这样user-service: /user-service/**


上面这种配置也是默认的配置,所以即使我们不配置,也能访问到。那么我们就来试试访问user-consumer这个微服务

正常访问,实际上我们也没有自己去配置。zuul会根据服务id来帮助我们提供这种配置。但是如果你希望忽略掉部分 服务id: 映射路径 那么该怎么做呢?另外希望加路由前缀怎么做呢?

zuul:routes: #服务id 映射路径           默认配置也是这样user-service: /user-service/**prefix: /api   #路由前缀ignored-services:   #忽略掉的服务- consumer-service


注意:这里加了前缀 /api 由于忽略掉了consumer-service服务,再来访问下

2.6 Zuul过滤器

Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。

2.6.1 ZuulFilter

ZuulFilter是过滤器的顶级父类。在这里我们看一下其中定义的4个最重要的方法:

public abstract ZuulFilter implements IZuulFilter{abstract public String filterType();abstract public int filterOrder();boolean shouldFilter();// 来自IZuulFilterObject run() throws ZuulException;// IZuulFilter
}
  • shouldFilter:返回一个Boolean值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
  • run:过滤器的具体业务逻辑。
  • filterType:返回字符串,代表过滤器的类型。包含以下4种:
    • pre:请求在被路由之前执行
    • routing:在路由请求时调用
    • post:在routing和errror过滤器之后调用
    • error:处理请求时发生错误调用
  • filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。

2.6.2 过滤器生命周期

  • 正常流程:

    • 请求到达首先会经过pre类型过滤器,而后到达routing类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。
  • 异常流程:
    • 整个过程中,pre或者routing过滤器出现异常,都会直接进入error过滤器,再error处理完毕后,会将请求交给POST过滤器,最后返回给用户。
    • 如果是error过滤器自己出现异常,最终也会进入POST过滤器,而后返回。
    • 如果是POST过滤器出现异常,会跳转到error过滤器,但是与pre和routing不同的时,请求不会再到达POST过滤器了。

景非常多:

  • 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
  • 异常处理:一般会在error类型和post类型过滤器中结合来处理。
  • 服务调用时长统计:pre和post结合使用。

2.6.3 自定义过滤器的使用

我们来自定义一个过滤器,模拟一个登录的校验。基本逻辑:如果请求中有access-token参数,则认为请求有效,放行。

package com.scu.filter;import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpServletRequest;@Component
public class LoginFilter extends ZuulFilter{@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;//pre}@Overridepublic int filterOrder() {//至少要确保拿到了参数 5 - 1return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;}@Overridepublic boolean shouldFilter() {return true;//返回true 使用拦截器}@Overridepublic Object run() throws ZuulException {//获取上下文RequestContext ctx = RequestContext.getCurrentContext();//获取requestHttpServletRequest request = ctx.getRequest();String token = request.getParameter("access-token");if(StringUtils.isBlank(token)){//登录校验失败   拦截 默认是truectx.setSendZuulResponse(false);//返回403状态码 禁止访问ctx.setResponseStatusCode(HttpStatus.FORBIDDEN.value());}return null;}
}


那么加上access-token参数试试,访问正常

2.7 Zuul的负载均衡与熔断

Zuul中默认就已经集成了Ribbon负载均衡和Hystix熔断机制。但是所有的超时策略都是走的默认值,比如熔断超时时间只有1S,很容易就触发了。因此建议我们手动进行配置:

hystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 3000
ribbon:ConnectionTimeout: 500ReadTimeout: 2000 #500*2+2000两个加起来*2不能超过timeoutInMillisecond
#  MaxAutoRetriesNextServer: 0 #不重试

重启后页面访问,查看日志,注意到warn的那行

2019-04-09 20:46:38.014  WARN 15792 --- [io-10086-exec-1] o.s.c.n.z.f.r.s.AbstractRibbonCommand    : The Hystrix timeout of 3000ms for the command user-service is set lower than the combination of the Ribbon read and connect timeout, 6000ms.

说的是hystrix的超时时间3000ms(针对user-service服务,实际上像上面那样写是针对所有服务的超时时间都是3000ms,如果是只针对user-service服务那么需要在之前补充user-service:后面不变),小于ribbon的读和连接超时时间6000毫秒

所以将hystrix的超时时间设置为6000ms吧,关于这个时间怎么计算的,查看AbstractRibbonCommand类的下方代码

         int ribbonReadTimeout = getTimeout(config, commandKey, "ReadTimeout",IClientConfigKey.Keys.ReadTimeout, RibbonClientConfiguration.DEFAULT_READ_TIMEOUT);int ribbonConnectTimeout = getTimeout(config, commandKey, "ConnectTimeout",IClientConfigKey.Keys.ConnectTimeout, RibbonClientConfiguration.DEFAULT_CONNECT_TIMEOUT);int maxAutoRetries = getTimeout(config, commandKey, "MaxAutoRetries",IClientConfigKey.Keys.MaxAutoRetries, DefaultClientConfigImpl.DEFAULT_MAX_AUTO_RETRIES);int maxAutoRetriesNextServer = getTimeout(config, commandKey, "MaxAutoRetriesNextServer",IClientConfigKey.Keys.MaxAutoRetriesNextServer, DefaultClientConfigImpl.DEFAULT_MAX_AUTO_RETRIES_NEXT_SERVER);ribbonTimeout = (ribbonReadTimeout + ribbonConnectTimeout) * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1);

SpringCloud(6):Feign与Zuul详解相关推荐

  1. SpringCloud分布式开发五大组件详解

    SpringCloud分布式开发五大组件详解 https://blog.csdn.net/weixin_40910372/article/details/89466955 服务发现--Netflix ...

  2. 九、SpringCloud基础微服务结构详解

    技术总结 架构图 一.系统架构演变 随着互联网的发展,网站应用的规模不断扩大.需求的激增,带来的是技术上的压力.系统架构也因此也不断的演进.升级.迭代.从单一应用,到垂直拆分,到分布式服务,到SOA, ...

  3. 【SpringCloud】简介及其核心组件详解

    一.什么是Spring Cloud [百度百科]--Spring Cloud是一系列框架的有序集合.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册.配置中 ...

  4. zuul 详解,带视频

    疯狂创客圈 Java 高并发[ 亿级流量聊天室实战]实战系列 [博客园总入口 ] 架构师成长+面试必备之 高并发基础书籍 [Netty Zookeeper Redis 高并发实战 ] 前言 Crazy ...

  5. Java基础学习总结(117)——Feign入门使用详解

    一,简介 Feign使得 Java HTTP 客户端编写更方便.Feign 灵感来源于Retrofit.JAXRS-2.0和WebSocket.Feign最初是为了降低统一绑定Denominator到 ...

  6. vagrant springcloud java 镜像:制作详解(带下载地址)

    狂创客圈 经典图书 : <Netty Zookeeper Redis 高并发实战> 面试必备 + 面试必备 + 面试必备 [博客园总入口 ] 疯狂创客圈 经典图书 : <Spring ...

  7. SpringCloud Alibaba Sentinel限流详解 这一次别在错过

    点赞再看,养成习惯,微信搜索[牧小农]关注我获取更多资讯,风里雨里,小农等你,很高兴能够成为你的朋友. 项目源码地址:公众号回复 sentinel,即可免费获取源码 熔断规则 在上一篇文章中我们讲解了 ...

  8. Zuul之Filter详解

    Zuul详解 官方文档:https://github.com/Netflix/zuul/wiki/How-it-Works Zuul的中心是一系列过滤器,能够在HTTP请求和响应的路由过程中执行一系列 ...

  9. SpringCloud分布式架构详解

    SpringCloud分布式架构详解 1. SpringCloud架构概述 1.1 SpringCloud架构简介 1.2 SpringBoot与SpringCloud依赖关系 1.3 SpringC ...

最新文章

  1. 2017 宋星大课堂福利赠票公布结果
  2. Magicodes.IE 在100万数据量下导入导出性能测试
  3. 为什么有些softmax公式需要减去输入中的最大值
  4. 【slowfast 减少ava数据集】将ava数据集缩小到2个,对数据集做训练,然后进行检测,为训练自己的数据集做准备
  5. python如何爬取sci论文中所需的数据_sci论文中的科研数据处理方法
  6. Linux用户管理案例(第二版)
  7. 皮亚诺曲线java,多维空间点索引算法概述
  8. SPOJ VLATTICE Visible Lattice Points(莫比乌斯反演)题解
  9. 【十五分钟Talkshow】如何理解并优化.NET应用程序对内存的使用
  10. linux获取电信超级密码吗,最新中国电信光猫超级密码获取方法
  11. 电感的两种模式——DCM和CCM的区别
  12. 二代测序方法:DNA测序之靶向重测序
  13. DruidDataSource配置说明
  14. mysql生日提醒_mysql生日提醒,闰年
  15. 移动硬盘文件丢失如何找回?
  16. 一些蓝桥杯的简单模拟题目
  17. Python判断字符串是否以字母开头
  18. 劫持网站防御技术,网站被劫持到其它网站的解决方法
  19. GD32F4xx创建工程
  20. 上海:IPTV进入三屏融合时代

热门文章

  1. gumbo库应用与按装
  2. 网络安全等级保护主要标准简要说明
  3. java nashorn_Java编程Nashorn实例代码
  4. 房地产开发流程与操作步骤
  5. 国际现货黄金的点差和持仓过夜费是什么意思
  6. 有了HTTP,为什么还要RPC?
  7. openGL学习笔记_配置开发环境第一个窗口
  8. Ribbon修改默认负载均衡策略
  9. 元宇宙时代下,虚实共生的智慧园区 | 凡拓x平安硅谷
  10. DSFD人脸检测算法的tensorflow实现