[TOC]

ZUUL 流程分析

开始

注解@EnableZuulProxy 上有一个 @Import(ZuulProxyMarkerConfiguration.class)-> 把 Maker初始化为Spring的Bean.

这时可以通过源码的注释,或者MATA-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration,\
org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* Responsible for adding in a marker bean to trigger activation of
* {@link ZuulProxyAutoConfiguration}. // 源码注释里有写
*
* @author Biju Kunjummen
*/

@Configuration(proxyBeanMethods = false)
public class ZuulProxyMarkerConfiguration {
@Bean
public Marker zuulProxyMarkerBean() {
return new Marker();
}
class Marker {
}
}

上面的两个类都是通过 @EnableAutoConfiguration加载, 这两个类上都有

1
@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class)

表示,要有这个Maker这个Bean才会加载,这就是开始的 EnableZuulProxy 开始的标志.

ZuulServerAutoConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Bean
@ConditionalOnMissingBean(name = "zuulServlet")
@ConditionalOnProperty(name = "zuul.use-filter", havingValue = "false",
matchIfMissing = true)
public ServletRegistrationBean zuulServlet() {
ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean<>(
new ZuulServlet(), this.zuulProperties.getServletPattern());
// The whole point of exposing this servlet is to provide a route that doesn't
// buffer requests.
servlet.addInitParameter("buffer-requests", "false");
return servlet;
}

@Bean
@ConditionalOnMissingBean(name = "zuulServletFilter")
@ConditionalOnProperty(name = "zuul.use-filter", havingValue = "true",
matchIfMissing = false)
public FilterRegistrationBean zuulServletFilter() {
final FilterRegistrationBean<ZuulServletFilter> filterRegistration = new FilterRegistrationBean<>();
filterRegistration.setUrlPatterns(
Collections.singleton(this.zuulProperties.getServletPattern()));
filterRegistration.setFilter(new ZuulServletFilter());
// 顺序为 Integer.MAX_VALUE
filterRegistration.setOrder(Ordered.LOWEST_PRECEDENCE);
// The whole point of exposing this servlet is to provide a route that doesn't
// buffer requests.
filterRegistration.addInitParameter("buffer-requests", "false");
return filterRegistration;
}

ZuulServletZuulServletFilter 是zuul提供的两种启动方式, 对应了servlet和servlet Filter. 通过配置文件切换,默认为ZuulServlet

1
2
zuul:
use-filter: true # ZuulServletFilter

这两种方式,处理逻辑基本是差不多的.关键是ZuulRunner,FilterProcessor核心处理类.

4种类型对应的ZuulFilter列表

1
2
# com.netflix.zuul.FilterLoader
private final ConcurrentHashMap<String, List<ZuulFilter>> hashFiltersByType = new ConcurrentHashMap<String, List<ZuulFilter>>();

ZuulServlet

com.netflix.zuul.http.ZuulServlet#service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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 {
// 按顺序执行 pre ZuulFilter
preRoute();
} catch (ZuulException e) {
// 按顺序执行 error ZuulFilter
error(e);
// 按顺序执行 post ZuulFilter
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 {
RequestContext.getCurrentContext().unset();
}
}

ZuulServletFilter

还有一个是. ZuulServletFilter 中 init 方法 生成了 ZuulRunner zuulRunner;

1
2
zuul:
use-filter: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
try {
// 按顺序执行 pre ZuulFilter
preRouting();
} catch (ZuulException e) {
// 按顺序执行 error ZuulFilter
error(e);
// 按顺序执行 post ZuulFilter
postRouting();
return;
}

// Only forward onto to the chain if a zuul response is not being sent
if (!RequestContext.getCurrentContext().sendZuulResponse()) {
filterChain.doFilter(servletRequest, servletResponse);
return;
}

try {
// 按顺序执行 route ZuulFilter
routing();
} catch (ZuulException e) {
// 按顺序执行 error ZuulFilter
error(e);
// 按顺序执行 post ZuulFilter
postRouting();
return;
}
try {
// 按顺序执行 post ZuulFilter
postRouting();
} catch (ZuulException e) {
// 按顺序执行 error ZuulFilter
error(e);
return;
}
} catch (Throwable e) {
error(new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_FROM_FILTER_" + e.getClass().getName()));
} finally {
RequestContext.getCurrentContext().unset();
}
}