⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 https://my.oschina.net/u/3300636/blog/851984 「源135」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

最近项目中使用zuul,zuul网上资料较少,顺便把源码看一遍分析一下。网上有几篇相关文章,已转载在博客中,这里再补充一点东西,应该就差不多了。这里讲的有点跳,如果zuul不熟悉,建议先看下zuul源码分析之Request生命周期管理 这篇文章。

zuul开启

首先由@EnableZuulProxy 注解是开启zuul的注解。

@EnableCircuitBreaker
@EnableDiscoveryClient
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
//引入zuul配置
@Import({ZuulProxyConfiguration.class})
public @interface EnableZuulProxy {
}

ZuulProxyConfiguration 继承了ZuulConfiguration

//该配置等同于xml中的beans
@Configuration
public class ZuulProxyConfiguration extends ZuulConfiguration {

@Configuration
@EnableConfigurationProperties({ZuulProperties.class})
//加载了ZuulServlet后才会加载该配置
@ConditionalOnClass({ZuulServlet.class})
@Import({ServerPropertiesAutoConfiguration.class})
public class ZuulConfiguration {

这两个类主要加载了四类东西:

1,注册zuulServlet,ZuulController 这是后面调用一些列zuulFilter的入口。

//ZuulController实现ServletWrappingController
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
ModelAndView var3;
try {
//此处调用zuulServlet中的方法
var3 = super.handleRequestInternal(request, response);
} finally {
RequestContext.getCurrentContext().unset();
}

return var3;
}

2,加载zuul各种自带的filter,比如preDecorationFilter、ribbonRoutingFilter等等

我这个版本中(1.1.2.RELEASE),zuul默认加载的filter有: pre类型的filter5个,route的3个,post的2个,共10个filter。 每个filter的功能这里就不详述了。

一些场景下,我们想要禁用掉部分过滤器,此时该怎么办呢?在网上看到了这个方法:

只需设置zuul.<SimpleClassName>.<filterType>.disable=true ,即可禁用SimpleClassName所对应的过滤器。以过滤器org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter为例,只需设置zuul.SendResponseFilter.post.disable=true ,即可禁用该过滤器。

3,加载ZuulFilterConfiguration,这个是定义在ZuulConfiguration中的Configuration。这个配置是将所有filter由ZuulFilterInitializer收集到FilterRegistry中。调用时,filter都是从这当中取的。

@Configuration
protected static class ZuulFilterConfiguration {
//按类型将所有ZuulFilter注入到map中
@Autowired
private Map<String, ZuulFilter> filters;

protected ZuulFilterConfiguration() {
}

@Bean
public ZuulFilterInitializer zuulFilterInitializer() {
return new ZuulFilterInitializer(this.filters);
}
}

4,加载ZuulRefreshListener、ZuulDiscoveryRefreshListener用于动态刷新zuul配置

p.s. 当应用启动时,加载顺序是:Configuration配置》ConditionalOnClass注解的bean》Configuration中的Configuration》自定义bean》Configuration中的bean》Configuration中的Configuration中的bean

zuul之filter调用

基本的调用顺序就不细说了,转载文章中介绍的比较详细。这里说一下zuul一个有点绕的地方。在ZuulServlet中

public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
try {
this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
RequestContext e = RequestContext.getCurrentContext();
e.setZuulEngineRan();

try {
this.preRoute();
} catch (ZuulException var12) {
this.error(var12);
this.postRoute();
return;
}

try {
this.route();
} catch (ZuulException var13) {
this.error(var13);
this.postRoute();
return;
}

try {
this.postRoute();
} catch (ZuulException var11) {
this.error(var11);
}
} catch (Throwable var14) {
this.error(new ZuulException(var14, 500, "UNHANDLED_EXCEPTION_" + var14.getClass().getName()));
} finally {
//清空上下文
RequestContext.getCurrentContext().unset();
}
}

如果执行pre类型的filter抛出ZuulException则执行error类型的filter,再执行post类型的filter

如果执行route类型的filter抛出ZuulException则执行error类型的filter,再执行post类型的filter

如果执行post类型的filter抛出ZuulException则执行error类型的filter

如果在抛出其他异常,或者在catch ZuulException后执行发生异常,则执行error类型的filter

这里有点绕,如果使用的时候需要注意一下。另外zuul许多默认的filter,虽然是zuul开发人员考虑周到,但在我们自己定制功能中,也可能造成麻烦。

666. 彩蛋

如果你对 Zuul 感兴趣,欢迎加入我的知识星球一起交流。

知识星球

文章目录
  1. 1. zuul开启
  2. 2. zuul之filter调用
  • 666. 彩蛋