通过前面几次的分享,我们了解了微服务架构的几个核心设施,通过这些组件我们可以搭建简单的微服务架构系统。比如通过Spring Cloud Eureka搭建高可用的服务注册中心并实现服务的注册和发现;

通过Spring Cloud Ribbon或Feign进行负载均衡;通过Spring Cloud Hystrix进行服务容错保护以避免故障蔓延。微服务搭建好了之后我们肯定会提供给外部系统一些统一的RESTFul API服务接口进行调用,

但是当外部系统调用我们的RESTful API的时候,怎么确定它需要的功能具体是哪个服务提供的呢?这个就涉及到一个路由规则和服务实例列表的维护问题。

这就引入了我们今天的主角--Spring Cloud Zuul,它是基于Netflix Zuul实现的API网关组件。它可以解决两个大问题:

  1. 就是我们上面提到的路由规则和服务实例的维护问题
  2. 对于一些校验(比如登录校验等)冗余问题。 按照我们的习惯的做法,是在每个服务中都需要加入这些校验,但是这样会导致代码冗余并且维护也比较麻烦,有了Spring Cloud Zuul这个网关服务之后,我们可以将这些共通的校验放到网关里面统一维护。

好,接下来我们就来看下怎么实现这个网关服务。

一、构建网关,配置路由

这里我们还是需要使用到前面的hello-service和feign-consumer服务。我们之前把feign-consumer作为服务消费者,但是别忘了在eureka体系里面,每个服务既是服务提供者又是服务消费者,所以feign-consumer也是一个服务提供者,并且http://localhost:9001/feign-consumer等接口就是它提供的服务。

接下来我们构建一个网关服务,代码结构如下:

  

代码实现步骤:

  1. 新建maven工程api-gateway
  2. 修改POM文件
    1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    2. <modelVersion>4.0.0</modelVersion>
    3. <groupId>com.sam</groupId>
    4. <artifactId>api-gateway</artifactId>
    5. <version>0.0.1-SNAPSHOT</version>
    6.  
    7. <parent>
    8. <groupId>org.springframework.boot</groupId>
    9. <artifactId>spring-boot-starter-parent</artifactId>
    10. <version>1.5.1.RELEASE</version>
    11. </parent>
    12.  
    13. <properties>
    14. <javaVersion>1.8</javaVersion>
    15. </properties>
    16. <!-- 使用dependencyManagement进行版本管理 -->
    17. <dependencyManagement>
    18. <dependencies>
    19. <dependency>
    20. <groupId>org.springframework.cloud</groupId>
    21. <artifactId>spring-cloud-dependencies</artifactId>
    22. <version>Camden.SR6</version>
    23. <type>pom</type>
    24. <scope>import</scope>
    25. </dependency>
    26. </dependencies>
    27.  
    28. </dependencyManagement>
    29.  
    30. <dependencies>
    31. <!-- 引入zuul依赖 , 它依赖了spring-boot-starter-actuator/spring-boot-starter-hystrix/spring-boot-starter-ribbon-->
    32. <dependency>
    33. <groupId>org.springframework.cloud</groupId>
    34. <artifactId>spring-cloud-starter-zuul</artifactId>
    35. </dependency>
    36.  
    37. </dependencies>
    38.  
    39. </project>
  3. 新建启动类
    1. /**
    2. * @EnableZuulProxy 开启Zuul 的API网关服务功能
    3. *
    4. */
    5. @EnableZuulProxy
    6. @SpringCloudApplication
    7. public class GateWayApp {
    8.  
    9. public static void main(String[] args) {
    10. SpringApplication.run(GateWayApp.class, args);
    11. }
    12. }
  4. 新建application.properties
    1. server.port=5555
    2. spring.application.name=api-gateway
    3.  
    4. #增加路由规则的配置
    5. #通过zuul.routes.<route>.path和zuul.routes.<route>.url进行配置,<route>为路由的名字,可以任意指定,但是一组path和url的路由名要相同
    6. #如下面的例子:所有满足/api-a/** 规则的访问都会被路由转发到//localhost:9001的地址
    7. #也就是说,我们访问http://localhost:5555/api-a/hello的时候,API网关服务就会将该请#求路由到 http://localhost:9001/hello提供的微服务接口上
    8. zuul.routes.api-a.path=/api-a/**
    9. zuul.routes.api-a.url=http://localhost:9001
    10.  
    11. zuul.routes.api-b.path=/api-b/**
    12. zuul.routes.api-b.url=http://localhost:9090
  5. 测试,启动eureka、hello-service、feign-consumer以及本次新加的api-gateway服务,然后访问http://localhost:5555/api-a/feign-consumer

    成功访问到了feign-consumer的服务接口--feign-consonsumer。

以上步骤实现了传统路由的配置,这种配置有个大的缺点,就是需要手工在application.properties文件中进行路由规则的配置,当服务很多的时候,维护工作量就会很大。为了减小维护成本,还有另外一种路由--面向服务的路由。

二、面向服务的路由

Spring Cloud Zuul和Eureka进行整合,我们可以让路由的path不是映射具体的url,而是具体的某个服务,而服务的url则交给Eureka服务发现机制自动维护,这类路由就是面向服务的路由。具体代码配置如下:

  1. 修改POM文件,引入Eureka依赖

    1. <!-- 引入eureka依赖 -->
    2. <dependency>
    3. <groupId>org.springframework.cloud</groupId>
    4. <artifactId>spring-cloud-starter-eureka</artifactId>
    5. </dependency>
  2. 修改application.properties配置文件
    1. server.port=5555
    2. spring.application.name=api-gateway
    3.  
    4. zuul.routes.api-a.path=/api-a/**
    5.  
    6. #这里用serviceId代替url,用服务名代替ip+端口号
    7. zuul.routes.api-a.serviceId=hello-service
    8.  
    9. eureka.client.service-url.defaultZone=http://localhost:1111/eureka

    注意:zuul.routes.api-a.url=hello-service也能实现功能,但是它不能进行正常的负载均衡和容错保护。

  3. 测试,访问http://localhost:5555/api-a/hello

    访问成功。

 三、服务路由的默认规则

在面向服务的路由中,由于<route>名字是随意起的,那么是不是可以这样:

  1. zuul.routes.hello-service.path=/hello-service/**
  2. zuul.routes.hello-service.serviceId=hello-service

<route>名字就是服务名,其实在实际的应用中,我们往往就是这样命名的。如果有这样的规则的话,那Zuul就可以帮我们默认实现这样的功能,进一步省去了配置的麻烦。

我们来做个实验,将配置文件改为:

  1. server.port=5555
  2. spring.application.name=api-gateway
  3.  
  4. eureka.client.service-url.defaultZone=http://localhost:1111/eureka

然后页面访问验证

访问成功。

但是由于默认情况下,Eureka上的服务都会被Zuul创建默认的映射关系来进行路由,使得我们不想对外开放的服务也被外部访问到,这个时候可以通过配置zuul.ignored-services来进行配置不需要自动创建路由的规则。当zuul.ignored-services=*的时候,所有的服务都不会自动创建路由规则,这个时候需要通过前面的配置进行相关路由配置了。

================华丽的分割线===================

前面说了那么多都是围绕一个问题展开的:路由规则和服务实例的维护问题,那么怎么解决第二个问题(校验冗余问题)呢?

四、请求过滤

为了在API网关中实现对客户端请求的校验,我们可以通过过滤器来实现对请求的拦截和过滤,实现方法比较简单,只需要继承ZuulFilter抽象类并实现其四个方法就行了。

修改api-gateway:

  1. 新增过滤器类

    1. /**
    2. * 继承ZuulFilter,并且实现其4个接口
    3. *
    4. * 用来进行请求过滤
    5. *
    6. */
    7. public class AccessFilter extends ZuulFilter {
    8. Logger logger = LoggerFactory.getLogger(AccessFilter.class);
    9. /*
    10. * shouldFilter 判断该过滤器是否需要被执行
    11. *
    12. * 这里直接返回true,表示该过滤器对所有请求都会生效。
    13. * 实际运用中我们可以利用该函数指定过滤器的有效范围
    14. */
    15. @Override
    16. public boolean shouldFilter() {
    17. return true;
    18. }
    19.  
    20. /*
    21. * 过滤器的具体逻辑
    22. *
    23. * 这里我们通过ctx.setSendZuulResponse(false)让zuul过来请求,不对其进行路由
    24. * 然后通过ctx.setResponseStatusCode(401)设置了返回的错误码
    25. *
    26. */
    27. @Override
    28. public Object run() {
    29. RequestContext context = RequestContext.getCurrentContext();
    30. HttpServletRequest request = context.getRequest();
    31. Object accessToken = request.getParameter("accessToken");
    32.  
    33. logger.info("send {} request to {}", request.getMethod(),request.getRequestURL().toString());
    34. if(accessToken == null) {
    35. context.setSendZuulResponse(false);
    36. context.setResponseStatusCode(401);
    37. }
    38.  
    39. return null;
    40. }
    41.  
    42. /* filterType 返回过滤器类型
    43. * 他决定了过滤器在请求的哪个生命周期中执行。这里定义为pre,代表会在请求被路由前执行。
    44. *
    45. * pre:请求执行之前filter
    46. * route: 处理请求,进行路由
    47. * post: 请求处理完成后执行的filter
    48. * error:出现错误时执行的filter
    49. */
    50. @Override
    51. public String filterType() {
    52. return "pre";
    53. }
    54.  
    55. /*
    56. * filterOrder 返回过滤器的执行顺序
    57. *
    58. * 当请求在一个阶段有多个过滤器是,需要根据该方法的返回值来依次执行
    59. *
    60. */
    61. @Override
    62. public int filterOrder() {
    63. return 0;
    64. }
    65.  
    66. }
  2. 修改启动类
    1. /**
    2. * @EnableZuulProxy 开启Zuul 的API网关服务功能
    3. *
    4. */
    5. @EnableZuulProxy
    6. @SpringCloudApplication
    7. public class GateWayApp {
    8.  
    9. //追加bean的是实现
    10. @Bean
    11. public AccessFilter accessFilter() {
    12. return new AccessFilter();
    13. }
    14. public static void main(String[] args) {
    15. SpringApplication.run(GateWayApp.class, args);
    16. }
    17. }
  3. 测试
    1. )访问http://localhost:5555/hello-service/hello,访问失败
    2. )访问http://localhost:5555/hello-service/hello?accessToken=token,正常访问

修改后的代码结构:

 五、拓展延伸

其实路由功能在真正运行时,他的路由映射和请求转发都是由几个不同的过滤器完成的。

路由映射主要通过pre类型的过滤器完成,他将请求路径与配置的路由规则进行匹配,找到需要转发的目标地址。

而请求转发的部分则是由route类型的过滤器完成的,对pre类型过滤器获取的路由地址进行转发。

所以,过滤器可以说是Zuul实现API网关功能最为核心的部件,每一个进入Zuul的HTTP请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。

spring cloud 入门系列六:使用Zuul 实现API网关服务的更多相关文章

  1. spring cloud 入门系列:总结

    从我第一次接触Spring Cloud到现在已经有3个多月了,当时是在博客园里面注册了账号,并且看到很多文章都在谈论微服务,因此我就去了解了下,最终决定开始学习Spring Cloud.我在一款阅读A ...

  2. spring cloud 入门系列四:使用Hystrix 实现断路器进行服务容错保护

    在微服务中,我们将系统拆分为很多个服务单元,各单元之间通过服务注册和订阅消费的方式进行相互依赖.但是如果有一些服务出现问题了会怎么样? 比如说有三个服务(ABC),A调用B,B调用C.由于网络延迟或C ...

  3. spring cloud 入门系列五:使用Feign 实现声明式服务调用

    一.Spring Cloud Feign概念引入通过前面的随笔,我们了解如何通过Spring Cloud ribbon进行负责均衡,如何通过Spring Cloud Hystrix进行服务断路保护,两 ...

  4. Spring Cloud 入门教程(六): 用声明式REST客户端Feign调用远端HTTP服务

    首先简单解释一下什么是声明式实现? 要做一件事, 需要知道三个要素,where, what, how.即在哪里( where)用什么办法(how)做什么(what).什么时候做(when)我们纳入ho ...

  5. Spring Cloud 入门系列(一)

    前言 Spring Could作为目前最流行基于Java开发的构建微服务的完整框架.发现目前相关系列教程太少,本文是基于官网教程做的一套翻译. 何为Spring Cloud? Spring Cloud ...

  6. spring cloud 入门系列一:初识spring cloud

    最近看到微服务很火,也是未来的趋势, 所以就去学习下,在dubbo和spring cloud之间我选择了从spring cloud,主要有如下几种原因: dubbo主要专注于微服务中的一个环节--服务 ...

  7. spring cloud 入门系列

    springcloud入门总结转发自:https://www.cnblogs.com/sam-uncle/p/9340390.html 最近看到微服务很火,也是未来的趋势, 所以就去学习下,在dubb ...

  8. spring cloud 入门系列八:使用spring cloud sleuth整合zipkin进行服务链路追踪

    好久没有写博客了,主要是最近有些忙,今天忙里偷闲来一篇. =======我是华丽的分割线========== 微服务架构是一种分布式架构,微服务系统按照业务划分服务单元,一个微服务往往会有很多个服务单 ...

  9. spring cloud 入门系列二:使用Eureka 进行服务治理

    服务治理可以说是微服务架构中最为核心和基础的模块,它主要用来实现各个微服务实例的自动化注册和发现. Spring Cloud Eureka是Spring Cloud Netflix 微服务套件的一部分 ...

随机推荐

  1. linux下JAVA开发的环境配置

    1.去http: //java.sun.com/j2se/1.4.2/download.html 下载一个Linux Platform的JDK,建议下载RPM自解压格式的(RPM in self-ex ...

  2. Android项目-高考作文功能简介(一)

    前言 :  开发安卓也已2年多了近3年了, 在自己刚入行的时候就有自己独立开发一个App的想法. 后来自己做了<<高考作文>>这一App. 后面续续断断的维护者. 也因为功能简 ...

  3. hadoop队列管理(指定queue跑程序)

    hadoop 升级到cdh5后,队列管理被取消,而是统一用资源池分配. hadoop2.0版本,Hadoop采用了平级队列组织方式,,管理员可将用户分到若干个扁平队列中,在每个队列中,可指定一个或几个 ...

  4. Uva - 177 - Paper Folding

    If a large sheet of paper is folded in half, then in half again, etc, with all the folds parallel, t ...

  5. Asp.net中JQuery、ajax调用后台方法总结

    通过上一篇文章实例的实现,整个过程当中学习到很多知识点,了解了Jquery.Ajax在asp.net中的运用,加以总结,其实原理都是一样的,理解了一种,其他的注意很少的区别就可以了.灵活运用: 1.有 ...

  6. Java 开源 CMS :magnolia

    Magnolia 是一个开源基于Java的Web内容管理系统(CMS),构建在Java内容知识库标准(JSR-170).在使用它的过程中,我发现它的界面确实很有特色:给人一种Win8的感觉.在此记录一 ...

  7. (十七)TableView的本地性能优化

    面试中常常会问TableView的性能优化. TableView只会加载能看到的Cell,每当有一个Cell进入视野范围内,就会调用. 存在着内存隐患,如果用户拖动的很快,所以内存会飙升的很快,因此要 ...

  8. Mahout系列之----距离度量

       x = (x1,...,xn) 和y = (y1,...,yn) 之间的距离为 (1)欧氏距离   EuclideanDistanceMeasure (2)曼哈顿距离  ManhattanDis ...

  9. 03_TortoiseGit冲突和补丁演示,补丁冲突

     1 下载TortoiseGit,下载地址: http://tortoisegit.soft32.com/free-download/ 2 创建一个GIT仓库 3 创建克隆,创建两个用于克隆的仓库 ...

  10. Demonstration of DB Query Analyzer 6.03 Installation and Running on Microsoft Windows 8

    Demonstration of DB Query Analyzer 6.03 Installation and Running on Microsoft Windows 8 Ma Genfeng ( ...