首先由@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所对应的过滤器。以过滤器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 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一个有点绕的地方。在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开发人员考虑周到,但在我们自己定制功能中,也可能造成麻烦。