大家好,又见面了,我是你们的朋友全栈君。
Zuul作为微服务系统的网关组件,用于构建边界服务,致力于动态的路由、过滤、监控、弹性伸缩和安全。
其中Zuul、Ribbon以及Eureka的结合使用可以实现智能路由和负载均衡的功能,网关将所有的服务的API接口统一聚合,统一对外暴露,外界调用API的接口的时候,不需要知道微服务系统中各服务相关调用的复杂性,保护了内部微服务单元的API接口,网关可以做用户身份认证和权限认证,防止非法请求操作api接口,网关可以实现监控功能,实时日志输出,对请求进行记录,网关可以实现流量监控,在高流量监控的情况下,对服务降级,API接口从内部服务分离出来,方便做测试
Zuul通过Servlet来实现,通过自定义的ZuulServlet来对请求进行控制,核心的是一系列过滤器,可以在http请求的发起和相应返回期间执行一系列的过滤器,Zuul采取了动态处理、编译等这些过滤器,过滤器之间不能直接通信,而是通过RequestContext(静态类)对象来实现共享数据,每个请求都会创建一个RequetsContext对象,RequestContext中又ThreadLocal变量来记录每个Request所需要传递的数据,底层使用的是ThreadLocalMap来进行存储数据的。
Zuul大部分功能都是通过过滤器来实现的,Zuul中定义了四种标准过滤器类型,这些过滤器类型的对应于请求的的典型生命周期。
1,PRE:这种过滤器在请求到达路由之前被调用,我们可以利用这种过滤器实现身份验证,在集群中选择请求的微服务,记录调试信息等。
2,ROUTING:这种过滤器将请求通过路由到达微服务,这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfinx Ribbon请求到微服务。
3,POST:这种过滤器在请求被路由到微服务以后执行,这种过滤器可用来响应添加标准的HTTP Header、收集统计信息和指标,将响应从微服务发送给客户端等。
4,ERROE:在其他阶段发生错误时执行该过滤器。
内置的特殊过滤器:
在zuul还提供了一类特殊的过滤器,分别为:StaticResponseFilter和SurgicaDebugFilter
StaticResponseFilter:允许从Zuul本身生成响应,而不是将请求转发到资源
SurgicaDebugFilter:允许将特定的请求路由到分隔的调试主机或者集群
自定义的过滤器:
除了默认的过滤器,Zuul还允许我们创建自定义的过滤器类型,例如可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务
可是有没有注意到,如果我们不使用zuul,当我们在每个微服务增加了新的方法,都需要在网关层手动的增加相应的方法封装,而Spring cloud 中的zuul很好的解决了这一问题
zuul作为网关层,自身也是一个微服务,跟其他服务Service-1. Service-2 。。。一样,都需要注册在Eureka Server上,可以相互发现,zuul都干知道那些服务在线,同时通过配置路由规则,可以将请求转发到指定的后端的服务上,对于一些公用的预处理,(比如:权限认证。token合法校验,灰度验证时部分流量引导之类)可以放在所谓的过滤器(ZuulFilter — 自定义的所谓的处理类)里处理,这样后端服务以后新增了,zuul层几乎可以保持不变。
Spring Cloud Zuul路由是微服务架构中不可缺少的一部分,提供动态路由,监控、弹性、安全等边缘服务,Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器
下面我们通过代码来了解Zuul是如何工作的:
简单实用
1,添加依赖
代码语言:javascript复制 <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
2,编写配置文件 application.yml
代码语言:javascript复制spring:
application:
name: gateway-service-zuul
server:
port: 8888
#增加路由规则的配置
#通过zuul.routes.<route>.path和zuul.routes.<route>.url进行配置,<route>为路由的名字,可以任意指定,但是一组path和url的路由名要相同
zuul.routes.baidu.path: /baidu/**
zuul.routes.baidu.url: http://www.baidu.com
3,设置启动类
代码语言:javascript复制package com.example.springzuul;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class SpringzuulApplication {
public static void main(String[] args) {
SpringApplication.run(SpringzuulApplication.class, args);
}
}
启动类上添加@EnableZuulProxy的注解,用于启动网关路由,最简单的Zuul案例就配置完成了
简单的Zuul配置完成之后,可是上面咱们在总结的时候,发现四种标准的过滤器咱们还么有使用到,下面讲解一下四种过滤器的使用情况,在使用的时候需要自己定义一个类,继承ZuulFilter类,并且覆盖里面的方法。
代码语言:javascript复制package com.example.springzuul;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import javax.servlet.http.HttpSession;
/**
* 自定义过滤器,可以实现在不同的时候进行数据的拦截,分为四种状态
* 当请求到达服务的时候,
* 请求进入服务的时候,
* 请求到达服务之后
* 错误的时候
*/
public class MyFilter extends ZuulFilter{
/**
* 表示返回的类型,就是确定要进行什么样的操作
* @return
*/
@Override
public String filterType() {
return null;
}
/**
* 设置级别,数字越大级别越低
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 表示是否开启当前的拦截器 false 是不开启, true是开启
* @return
*/
@Override
public boolean shouldFilter() {
return false;
}
/**
* 表示执行的代码,比如说请求的时候,进行身份的认证等..
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext currentContext = RequestContext.getCurrentContext();
// currentContext.set
HttpSession session = currentContext.getRequest().getSession();
return null;
}
}
自定义类之后,可以完成一些自己的配置
filterType:表示返回的类型,也就是需要说明你当前的拦截器是在什么时候使用。
filterOrder:设置优先级,因为会有很多的拦截器,并不是只有当前设置的一个拦截器,所以需要设置拦截的优先级,数字越大表示优先级越低
shouldFilter:表示设置是否开启拦截器,true是开启拦截器,false是不开启拦截器
run:就是拦截之后需要进行的操作,可以根据上面的filterType设置的类型,进行相应的操作,在使用的时候,使用到一个RequestContext的对象,该对象在上面也说过,因为拦截器之间是没有通讯的,所以使用RequestContet来进行数据的共享,当我在操作的时候,有一点像不明白,该对象里面的数据是在什么时候传递过来的呢,由于源码没有看懂也没有找打相似的代码,于是与网上寻找帮助,在看完资料之后,数据的传输是不是用过域来记性数据的保存和传输的呢,因为RequestContext对象可以获取到Request之后可以获取到Session对象,将数据保存到该对象中,可以完成在登录的时候获取用户的信息,也可以完成在拦截器中完成数据的共享,不知道想法是否正确,还希望大佬给出答案。
上面是是自定义的拦截器,但是如果需要时会用自己定义的拦截器,是否还需要将自己定义的拦截器放在spring的容器中呢,所以需要配置一个java配置。
代码语言:javascript复制package com.example.springzuul;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 用于将自己定义的拦截器,声明成bean注入到spring的容器中
*/
@Configuration
public class FilterConfig {
@Bean
public MyFilter myFilter() {
MyFilter myFilter = new MyFilter();
return myFilter;
}
}
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/170628.html原文链接:https://javaforall.cn