Netflix之Zuul的进阶应用(十八)

过滤器优先级

如图所示,数字越小,执行的优先级就越高:

图表展示出来就是:

过滤器 order 描述 类型
ServletDetectionFilter -3 检测请求是用 DispatcherServlet还是 ZuulServlet pre
Servlet30WrapperFilter -2 在Servlet 3.0 下,包装 requests pre
FormBodyWrapperFilter -1 解析表单数据 pre
SendErrorFilter 0 如果中途出现错误 error
DebugFilter 1 设置请求过程是否开启debug pre
PreDecorationFilter 5 根据uri决定调用哪一个route过滤器 pre
RibbonRoutingFilter 10

如果写配置的时候用ServiceId则用这个route过滤器,该过滤器可以用Ribbon

做负载均衡,用hystrix做熔断

route
SimpleHostRoutingFilter 100 如果写配置的时候用url则用这个route过滤 route
SendForwardFilter 500 用RequestDispatcher请求转发 route
SendResponseFilter 1000 用RequestDispatcher请求转发 post

为了能够更清晰地知道底层是怎么完成这一系列流程的,我们通过编写一个自定义的过滤器来测试。从我们上一篇博客Spring Cloud集群中使用Zuul(十七) 底部拿到源码。

依次运行四个项目的*App启动类,启动四个项目。

在eureka-zuul网关项目中,在com.init.springCloud包下创建filter包,新建SelfDefineFilter类,去继承Zuul框架的ZuulFilter类,实现内部方法。在图上的Route阶段,三种路由方式都继承了这个ZuulFilter:

package com.init.springCloud.filter;

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;

import com.netflix.zuul.ZuulFilter;

public class SelfDefineFilter extends ZuulFilter {

	@Override
	public Object run() {
		System.out.println("执行自定义过滤器");
		return null;
	}

	@Override
	public boolean shouldFilter() {
		//是否执行当前过滤器
		return true;
	}

	@Override
	public int filterOrder() {
		//执行顺序
		return 5;
	}

	@Override
	public String filterType() {
		//过滤器执行阶段的类型
		return FilterConstants.ROUTE_TYPE;
	}

}

按照Route阶段的执行顺序,我们规定自定义的路由过滤器执行顺序,在Route阶段比优先级最高的RibbonRoutingFilter还高(RibbonRoutingFilter为10,自定义路由过滤器为5)。

之后,编写一个配置类SelfDefineConf.class,把这个自定义的路由过滤器当成Spring的Bean组件注入进去:

package com.init.springCloud.filter;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SelfDefineConf {

	@Bean
	public SelfDefineFilter getFilter(){
		return new SelfDefineFilter();
	}
	
}

重新启动eureka-zuul项目,任意访问一个接口,譬如这里访问:http://localhost:9090/consumer/router或者http://localhost:9090/users/router,都可以看到Zuul内部执行了我们自定义的路由过滤器:


过滤器的动态加载

在一个大型项目中,由于网关接手了大部分的请求,所以它是一个不能随随便便就停止的项目,当我们涉及到有新的路由规则上线,又不能停止网关项目的时候,就可以使用过滤器的动态加载来完成这个操作。使用groovy可以实现在不停止网关项目的同时,动态加载我们自定义的过滤器,在eureka-zuul的pom.xml中加入groovy相关依赖:

<dependency>
	<groupId>org.codehaus.groovy</groupId>
	<artifactId>groovy-all</artifactId>
	<version>2.4.15</version>
</dependency>

接着在ZuulApp.class启动类里面配置zuul的动态加载过滤器规则:

@PostConstruct
public void zuulInit(){
	FilterLoader.getInstance().setCompiler(new GroovyCompiler());
	//过滤器的路径
	String scriptRoot = System.getProperty("zuul.filter.root","groovy/filters");
	//定时器时间,5秒刷新一次
	String refreshInterval = System.getProperty("zuul.filter.refreshInterval","5");
	if(scriptRoot.length() > 0){
		scriptRoot += File.separator;
	}
	try {
		FilterFileManager.setFilenameFilter(new GroovyFileFilter());
		FilterFileManager.init(Integer.parseInt(refreshInterval), 
				scriptRoot+"pre", scriptRoot+"route", scriptRoot+"post");
	} catch (Exception e) {
		e.printStackTrace();
	}
}

我们设置了过滤器读取的位置是groovy.filters,所以我们在src/main/java目录下创建groovy.filters包,并在这个包下创建三个包:pre、route、post(groovy只会读取这三个包下面的内容,源代码中把文件放在了外面的包里,不被读取)。之后启动项目。

接下来编写一个文件DynamicFilter.groovy,内容和我们上面自定义的过滤器类似,没有大的修改:

package groovy.filters;

import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;

import com.netflix.zuul.ZuulFilter;

class DynamicFilter extends ZuulFilter {

	@Override
	public Object run() {
		System.out.println("===>这里是用groovy实现的动态加载过滤器");
		return null;
	}

	@Override
	public boolean shouldFilter() {
		//是否执行当前过滤器
		return true;
	}

	@Override
	public int filterOrder() {
		//执行顺序
		return 3;
	}

	@Override
	public String filterType() {
		//过滤器执行阶段的类型
		return FilterConstants.ROUTE_TYPE;
	}

}

在项目启动之后,我们依然访问一下:http://localhost:9090/users/router,可以看到控制台使用了我们自定义的路由规则。接着我们把这个DynamicFilter.groovy文件拖拽到groovy.filters.route包下,等待5秒左右,再次访问:http://localhost:9090/users/router,就可以看到zuul已经动态加载了我们配置的过滤器了:


@EnableZuulServer 


和@EnableZuulProxy对应的还有一个@EnableZuulServer,功能相差不多,相当于是一个简化版本,缺失了灰色字体标注的项目。

源码点击这里

Spring Cloud系列:

Spring Cloud介绍与环境搭建(一)

Spring Boot的简单使用(二)

Spring Cloud服务管理框架Eureka简单示例(三)

Spring Cloud服务管理框架Eureka项目集群(四)

Spring Cloud之Eureka客户端健康检测(五)

Netflix之第一个Ribbon程序(六)

Ribbon负载均衡器详细介绍(七)

Spring Cloud中使用Ribbon(八)

具有负载均衡功能的RestTemplate底层原理(九)

OpenFeign之第一个Feign程序(十)

OpenFeign之feign使用简介(十一)

Spring Cloud中使用Feign(十二)

Netflix之第一个Hystrix程序(十三)

Netflix之Hystrix详细分析(十四)

Spring Cloud中使用Hystrix(十五)

Netflix之第一个Zuul程序(十六)

Spring Cloud集群中使用Zuul(十七)

Netflix之Zuul的进阶应用(十八)

消息驱动之背景概述(十九)

消息中间件之RabbitMQ入门讲解(二十)

消息中间件之Kafka入门讲解(二十一)

Spring Cloud整合RabbitMQ或Kafka消息驱动(二十二)

相关文章
相关标签/搜索