目录
自定义ZuulFilter
public class MyZuulFliter extends ZuulFilter {
/**
* 过滤类型
*
* @return 过滤类型字符串
*/
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
/**
* 过滤器的执行顺序
*
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 是否执行过滤器
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 过滤器执行逻辑
*
* @return 无关紧要
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("Entered MyZuulFilter run Method");
/*
获取当前请求上下文
该请求上下文已经被其他过滤器封装好 可以直接拿过来使用
*/
RequestContext requestContext = RequestContext.getCurrentContext();
//获取当前请求域对象
HttpServletRequest request = requestContext.getRequest();
String method = request.getMethod();
String URL = request.getRequestURL().toString();
System.out.println("method: " + method + ",url " + URL);
return null;
}
}
执行http://localhost:5000/eureka-client-api/info 打印如下 此时过滤器执行成功
@EnableZuulProxy
当我们在启动类上加了@EnableZuulProxy 注解时 可以观察其内部结构
/**
*设置一个Zuul服务器端点并在其中安装一些反向代理过滤器,以便它可以将请求转发到后端服务器。
后端可以通过配置或DiscoveryClient手动注册。
*
* @see EnableZuulServer for how to get a Zuul server without any proxying
*
* @author Spencer Gibb
* @author Dave Syer
* @author Biju Kunjummen
*/
@EnableCircuitBreaker
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyMarkerConfiguration.class) //导入maker类
public @interface EnableZuulProxy {
}
ZuulProxyAutoConfiguration
由前面课程可知自动装配有两个条件构成一个是spring.factories第二个是@ConditionalOnxxx。当我们在启动类加上了@EnableZuulProxy 注解此时ZuulProxyAutoConfiguration 就会被自动装配
ZuulProperties
我们在yml中配置的属性都被封装到改类当中
内置过滤器
error过滤器内置到post 因为最后响应还是到post过滤器当中 由上我们可以看出当zuul在过滤各个阶段执行的过滤器,各个阶段的过滤器的执行顺序是根据filterOrder()来决定的。内置过滤器和我们自己定义的一样
过滤器执行流程
ZuulServlet
核心zuulservlet初始化器并协调zuullter的执行

/*
该方法是核心方法 用来在请求初始化zuul网关各个阶段的的Filter
*/
@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
try {
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
// Marks this request as having passed through the "Zuul engine", as opposed to servlets
// explicitly bound in web.xml, for which requests will not have the same data attached
RequestContext context = RequestContext.getCurrentContext();
context.setZuulEngineRan();
try {
/*
per前置阶段 此时他会去调用ZuulRunner.preRoute() 方法
preRoute 会去调用FilterProcessor.route()方法
*/
preRoute();
} catch (ZuulException e) {
error(e);
postRoute();
return;
}
try {
route();
} catch (ZuulException e) {
error(e);
postRoute();
return;
}
try {
postRoute();
} catch (ZuulException e) {
error(e);
return;
}
} catch (Throwable e) {
error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
} finally {
//取消设置threadLocal上下文。在请求结束时完成。
RequestContext.getCurrentContext().unset();
}
}
FilterProcessor
doc
这是执行过滤器的核心类。
这里面定义了4个用来判断当前filter的FilterType()返回类型的方法
/**
* runs "post" filters which are called after "route" filters. ZuulExceptions from ZuulFilters are thrown.
* Any other Throwables are caught and a ZuulException is thrown out with a 500 status code
*
* @throws ZuulException
*/
public void postRoute() throws ZuulException {
try {
runFilters("post");
} catch (ZuulException e) {
throw e;
} catch (Throwable e) {
throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_POST_FILTER_" + e.getClass().getName());
}
}
/**
* runs all "error" filters. These are called only if an exception occurs. Exceptions from this are swallowed and logged so as not to bubble up.
*/
public void error() {
try {
runFilters("error");
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
}
/**
* Runs all "route" filters. These filters route calls to an origin.
*
* @throws ZuulException if an exception occurs.
*/
public void route() throws ZuulException {
try {
runFilters("route");
} catch (ZuulException e) {
throw e;
} catch (Throwable e) {
throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_ROUTE_FILTER_" + e.getClass().getName());
}
}
runFilters筛选器
/**
* 运行筛选器类型的所有筛选器sType/在筛选器中使用此方法按类型运行自定义筛选器
*
改方法将相同类型的过滤器链接放到set集合
* @param sType the filterType.
* @return
* @throws Throwable throws up an arbitrary exception
*/
public Object runFilters(String sType) throws Throwable {
if (RequestContext.getCurrentContext().debugRouting()) {
Debug.addRoutingDebug("Invoking {" + sType + "} type filters");
}
boolean bResult = false;
List<ZuulFilter> list = FilterLoader.getInstance().getFiltersByType(sType);
if (list != null) {
//依次执行该阶段的过滤器
for (int i = 0; i < list.size(); i++) {
ZuulFilter zuulFilter = list.get(i);
//执行每个过滤器的run方法前提 shouldFilter为true
//执行成功和失败会有不同操作
Object result = processZuulFilter(zuulFilter);
if (result != null && result instanceof Boolean) {
bResult |= ((Boolean) result);
}
}
}
return bResult;
}
当网关在接收到请求此时处于pre前置状态此时会先处理前置过滤器的内容
此时preRoute() 判断出属于前置方法此时就会去执行前置的所有过滤器
此时pre阶段执行的过滤器有6个
processZuulFilter
该方法处理一个单独的ZuulFilter。此方法添加调试信息。通俗来说就是用来执行当前单独的filter然后对其成功失败做对应处理
public Object processZuulFilter(ZuulFilter filter) throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
boolean bDebug = ctx.debugRouting();
final String metricPrefix = "zuul.filter-";
long execTime = 0;
String filterName = "";
try {
long ltime = System.currentTimeMillis();
filterName = filter.getClass().getSimpleName();
RequestContext copy = null;
Object o = null;
Throwable t = null;
if (bDebug) {
Debug.addRoutingDebug("Filter " + filter.filterType() + " " + filter.filterOrder() + " " + filterName);
copy = ctx.copy();
}
/*
运行过滤器检查!isFilterDisabled()和shouldFilter()。如果两者都为true,
则调用当前filter 的run()方法。
*/
ZuulFilterResult result = filter.runFilter();
//获取状态判断是否成功
ExecutionStatus s = result.getStatus();
//用时时长
execTime = System.currentTimeMillis() - ltime;
switch (s) {
case FAILED: //失败处理
t = result.getException();
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
break;
case SUCCESS: //成功处理
o = result.getResult();
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.SUCCESS.name(), execTime);
if (bDebug) {
Debug.addRoutingDebug("Filter {" + filterName + " TYPE:" + filter.filterType() + " ORDER:" + filter.filterOrder() + "} Execution time = " + execTime + "ms");
Debug.compareContextState(filterName, copy);
}
break;
default:
break;
}
if (t != null) throw t;
//通知线程 当前filter执行完成
usageNotifier.notify(filter, s);
return o;
} catch (Throwable e) {
if (bDebug) {
Debug.addRoutingDebug("Running Filter failed " + filterName + " type:" + filter.filterType() + " order:" + filter.filterOrder() + " " + e.getMessage());
}
usageNotifier.notify(filter, ExecutionStatus.FAILED);
if (e instanceof ZuulException) {
throw (ZuulException) e;
} else {
ZuulException ex = new ZuulException(e, "Filter threw Exception", 500, filter.filterType() + ":" + filterName);
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
throw ex;
}
}
}
此时一个filter完整执行完成 FilterProcessor执行当前阶段第二个filter
各个阶段运行逻辑一致 当Filter初始化,请求完成后
总结
当客户端在发送请求时Zuul会开辟一个线程池 线程执行时ZuulServlet.server方法拦截到对应请求此时该方法会调用FilterProcessor中的方法依次初始化zuul的pre,rout,post,error各个阶段的过滤器。当过滤器执行过滤完请求后,请求响应 执行结束。