SpringCloud(七)Zuul——网关与路由

目录

1 引言

2. Zuul

2.1  Zuul简介

2.2 实战

2.2.1 简单实例

2.2.2 Zull指定path + serviceId

2.2.3 Zuul指定path + url

2.2.4 Zuul路由的strip-prefix

2.2.5 Zuul使用正则表达式 

2.2.6 Zuul的Filter

扫描二维码关注公众号,回复: 9039249 查看本文章

1 引言

源码托管地址:https://github.com/cddofficial/SpringCloudRepo

到这里我们的Spring Cloud微服务架构基本的东西已经说的过半了。在前面的文章中,我们创建了很多微服务,总的来说有3种:一个服务注册中心微服务,一个用户微服务,一个可乐微服务。其他的先不记。

我们可以直接访问用户微服务,可以直接可乐微服务,访问每个都有不同的访问路径。至此看来,我们搭建的Spring Cloud微服务还是散的,还是一个个springboot项目。那么我们怎么能让外界看起来我们的这些微服务是一个整体的系统呢?如何做到给外界只留下一个访问入口,而我们架构内部可以有一套调用规则来实现一个完整的业务逻辑呢?

架构图如下:

我们要创建一个网关微服务,这样我们的买可乐的微服务就只有一个请求入口,那就是网关了。等网关接收到请求后,具体要调用哪个微服务就是我们这个微服务内部的事情了。等处理完之后再把响应消息返回给网关,由网关统一返回给请求发起端。这整个流程外部并不知情。这个情况下对于外部来说,我们这个微服务架构系统就是一个单独的系统。

我们今天就来说说这个网关微服务,主要实现技术Zuul,当一个请求来到网关时,就是Zull来决定接下来该调哪个微服务。请继续往下看。

2. Zuul

2.1  Zuul简介

Zuul是netflix的基于jvm的路由器和服务器顿负载均衡。Netflix 将Zuul 用于下面的用途:

  • Authentication
  • Insights
  • Stress Testing
  • Canary Testing
  • Dynamic Routing
  • Service Migration
  • Load Shedding
  • Security
  • Static Response handling
  • Active/Active traffic management

参考官方文档:https://cloud.spring.io/spring-cloud-static/Finchley.SR4/single/spring-cloud.html#netflix-zuul-starter

2.2 实战

2.2.1 简单实例

1 复制得到eureka-client-gateway-zuul微服务

复制eureka-server-service-discover微服务重命名为eureka-client-gate-zuul(至于如何复制这里不再赘述,请看eureka——实战中的 “2.4.1 创建可乐微服务” 的 “复制得到eureka-client-coke)导入到IDE工具里面,导入后项目结构如下图:

2 修改eureka-client-gateway-zuul微服务

(1)修改pom文件

pom文件中删掉eureka server依赖,添加eureka client依赖和Zuul依赖,截图如下:

整个pom文件代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.7.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>

	<groupId>com.cdd.cloud</groupId>
	<artifactId>eureka-client-gateway-zuul</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>eureka-server-service-discover</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

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

		<!-- Zuul依赖 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
		</dependency>

		<!-- test依赖 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<!-- 引入spring cloud的依赖,不能少,主要用来管理Spring Cloud生态各组件的版本 -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Finchley.SR2</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<!-- 添加spring-boot的maven插件,不能少,打jar包时得用 -->
	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

(2)修改启动类

修改启动类名称为:EurekaClientGatewayZuulApplication,启动类上删掉@EnableEurekaServer 注解,添加@EnableZuulProxy注解。启动类代码如下:

package com.cdd.demo;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
 
@SpringBootApplication
@EnableZuulProxy   // 启用Zuul注解
public class EurekaClientGatewayZuulApplication {
 
	public static void main(String[] args) {
		SpringApplication.run(EurekaClientGatewayZuulApplication.class, args);
	}
}	

(3)修改application.yml文件

修改后的application.yml文件内容如下:

server:
  port: 8080

spring:
  application:
    name: eureka-client-gateway-zuul
    
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}  #实例id

3. 启动服务

启动服务注册中心服务eureka-server-service-discover,再启动用户微服务的2个实例(指定不用端口分别启动2次),启动eureka-client-coke-feign微服务,启动网关微服务eureka-client-gateway-zuul。启动完成后先来看下服务注册列表,保证所有服务都启动成功了。服务注册列表如下图:

4 测试

这个时候我们的网关微服务已经有了并且启动成功了,会把服务注册列表里面除过自己的服务都扫描到。可以根据

网关IP + 网关端口 + 其他服务应用名称 + 该服务里的请求路径 去访问该服务的接口。

例如,访问用户微服务,浏览器请求:http://localhost:8080/eureka-client-user/user/1 ,响应页面如下:

上面这个访问的请求路径有点太长了,能不能短点呢,当然是可以的,我们在yml文件中添加下面部分代码:

这里的eureka-client-user来自于服务注册列表localhost:8761中的下面红色框部分(serviceId也指的是这部分,下面就不再解释了),或者来自于application.yml中的spring.application.name属性值,如下图:

现在重启网关微服务eureka-client-gateway-zuul,启动成功后。

在浏览器去请求:http://localhost:8080/user/user/1,就可以了,相当于该请求路径中第一个user把刚才的eureka-client-user替换了,响应页面如下:

当热了,现在去访问http://localhost:8080/eureka-client-user/user/1也是可以的。

 

5, 不让某个微服务被路由映射到

如果我们不想让网关路由到服务注册列表里的其他某个服务,可以这样做,如下图:

 

2.2.2 Zull指定path + serviceId

根据path + serviceId去路由。在application.yml中修改zuul配置内容,截图如下:

重新启动eureka-client-gateway-zuul微服务,浏览器访问:http://localhost:8080/coke-path/coke/2,响应页面如下:

2.2.3 Zuul指定path + url

根据path + url去路由。在application.yml中修改zuul配置内容(这种不推荐使用,把url都定死了,如果该微服务多个节点呢),截图如下:

重新启动eureka-client-gateway-zuul微服务,浏览器访问:http://localhost:8080/coke-url/coke/3,响应页面如下:

2.2.4 Zuul路由的strip-prefix

在application.yml中修改zuul配置指定访问路径前缀内容,截图如下:

重新启动eureka-client-gateway-zuul微服务,浏览器访问:http://localhost:8080/api/eureka-client-user/user/1,响应页面如下:

2.2.5 Zuul使用正则表达式 

1.删除applicaton.yml中关于zuul的配置

修改后application.yml整个内容如下:

server:
  port: 8080

spring:
  application:
    name: eureka-client-gateway-zuul
    
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}  #实例id

2.注册添加PatternServiceRouteMapper的Bean

在启动类中添加serviceRouteMapper方法,截图如下:

整个启动类代码如下:

package com.cdd.demo;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.cloud.netflix.zuul.filters.discovery.PatternServiceRouteMapper;
import org.springframework.context.annotation.Bean;
 
@SpringBootApplication
@EnableZuulProxy   // 启用Zuul注解
public class EurekaClientGatewayZuulApplication {
 
	public static void main(String[] args) {
		SpringApplication.run(EurekaClientGatewayZuulApplication.class, args);
	}
	
	// 注册PatternServiceRouteMapper的bean
	@Bean
	public PatternServiceRouteMapper serviceRouteMapper() {
	    return new PatternServiceRouteMapper(
	        "(?<name>^.+)-(?<version>v.+$)",
	        "${version}/${name}");
	}
}	

3. 修改eureka-client-coke-feign微服务

修改application.yml文件中应用名称,修改为:eureka-client-coke-v1,只修改这部分。截图如下:

4.启动服务

重新启动eureka-client-coke-feign微服务,eureka-client-gateway-zuul微服务(服务注册中心服务,用户微服务的2个实例也要在运行状态,哪个没运行,就先启动吧)

5.测试

在浏览器中访问:http://localhost:8080/v1/eureka-client-coke/coke/2,响应页面如下:

正好正则表达式匹配上了,也访问成功了。测试完了,把微服务eureka-client-coke-feign-hystrix的应用名称再改回去,改为:

eureka-client-coke-feign-hystrix。把eureka-client-gateway-zuul网关微服务启动类里面的serviceRouteMapper方法注释调。

2.2.6 Zuul的Filter

1 简介

我们这里要说的filter可不是servlet里面的filter,Zuul的大部分功能都是通过过滤器实现的。zuul中定义了4种类型的过滤器,这些过滤器类型对应于请求的典型生命周期。

PRE,这种过滤器在请求被路由之前调用。我们可以利用这种过滤器来实现身份验证,在集群中选择请求的微服务,记录调试信息等。

ROUTING:,这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache

HttpClient或netflix Ribbon请求微服务。

POST,这种过滤器在请求路由到微服务后执行。这种过去可用来响应标准的http header,收集统计信息和指标,将响应从微服务发给客户端等。

ERROR,在其他阶段发生错误时执行该过滤器。

除了默认的过滤器,zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在zuul中生成响应,而不将请求转发到后端的微服务。

filter生命周期图如下:

2 实战

(1)复制得到eureka-client-gateway-zuul-filter微服务

复制eureka-client-gateway-zuul微服务重命名为eureka-client-gateway-zuul-filter微服务(如何复制?请看上面“2.2 实战”中的“2.2.1简单实例”中的第1步),并且导入到IDE工具中,导入后项目结构如下图:

(2)新建PreZuulFilter类

在com.cdd.demo包(启动类所在的包)下新建一个filter包,在该包下新建一个PreZuulFilter类,该类代码如下:

package com.cdd.demo.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;

public class PreZuulFilter extends ZuulFilter {

	@Override
	public boolean shouldFilter() {
		// 要用这个过滤器吗?用-true;不用-false
		return true;
	}

	// 实现业务逻辑
	@Override
	public Object run() throws ZuulException {
		 System.out.println("这里是PreFilter的run方法");
		return null;  // 一般情况这里都是返回null
	}

	@Override
	public String filterType() {
		// zuul过滤器的类型
		return "pre";
	}

	@Override
	public int filterOrder() {
		// 这个过滤器执行的顺序,数字越大越靠后
		return 2;
	}

}

(3)修改启动类。

修改启动类的名称为:EurekaClientGatewayZuulFilterApplication,添加preZuulFilter()方法。启动类代码如下:

package com.cdd.demo;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

import com.cdd.demo.filter.PreZuulFilter;
 
@SpringBootApplication
@EnableZuulProxy   // 启用Zuul注解
public class EurekaClientGatewayZuulFilterApplication {
 
	public static void main(String[] args) {
		SpringApplication.run(EurekaClientGatewayZuulFilterApplication.class, args);
	}
	
	// 注册到spring容器中
	@Bean
	public PreZuulFilter preZuulFilter() {
		return new PreZuulFilter();
	}
}	

(4)启动服务。

启动服务注册中心服务eureka-server-service-discover,启动用户微服务eureka-client-user(启动一个实例就行),启动

eureka-client-gateway-zuul-filter微服务。启动完成后,先来看下服务注册列表,浏览器访问:http://localhost:8761/ ,响应页面如下:

(5)测试

先把eureka-client-gateway-zuul-filter微服务的控制台日志清空了。

浏览器中通过网关调用用户微服务,访问:http://localhost:8080/eureka-client-user/user/3 ,响应页面放回数据正常,页面如下:

再来看下eureka-client-gateway-zuul-filter微服务的控制台日志,的确打印出来了刚才编写的那句话,如下图:

到这里我们Zuul就说的差不多了。光靠前面这些东西我们已经可以搭建一个能上生产的spring cloud微服务架构的系统了。当热了,还有很多东西没说呢。对于这篇文章或是前面的文章大家有任何建议和疑问欢迎来一起讨论。

发布了45 篇原创文章 · 获赞 28 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/weixin_41968788/article/details/103274471