Zuul源码分析
温馨提示
版本:zuul - 2.2.0.M3
jdk 1.8
Zuul
zuul组件图
在zuul中, 整个请求的过程是这样的,首先将请求给zuulservlet处理,zuulservlet中有一个zuulRunner对象,该对象中初始化了RequestContext:作为存储整个请求的一些数据,并被所有的zuulfilter共享。zuulRunner中还有 FilterProcessor,FilterProcessor作为执行所有的zuulfilter的管理器。FilterProcessor从filterloader 中获取zuulfilter,而zuulfilter是被filterFileManager所加载,并支持groovy热加载,采用了轮询的方式热加载。有了这些filter之后,zuulservelet首先执行的Pre类型的过滤器,再执行route类型的过滤器,最后执行的是post 类型的过滤器,如果在执行这些过滤器有错误的时候则会执行error类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。
参考 https://blog.csdn.net/forezp/article/details/76211680
- Authentication
- Insights
- Stress Testing
- Canary Testing
- Dynamic Routing
- Service Migration
- Load Shedding
- Security
- Static Response handling
- Active/Active traffic management
@EnableZuulProxy与@EnableZuulServer 之间的区别
- 前者可以与Eureka、Ribbon集成,后者是单独的zuul服务器。
启动zuul代理
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
跟进源码 —>>>>> EnableZuulProxy
@EnableCircuitBreaker // Hystric启动 启动容错
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({ZuulProxyMarkerConfiguration.class})
public @interface EnableZuulProxy {
}
zuul设计者这么做我认为他只是为了做条件装配 ,在使用需要装配的类上面通过ConditionXXX -->>> Marker
CondtionXXX 属于springboot的知识、他是基于spring的condtion接口做的实现。
public class ZuulProxyMarkerConfiguration {
public ZuulProxyMarkerConfiguration() {
}
@Bean
public ZuulProxyMarkerConfiguration.Marker zuulProxyMarkerBean() {
return new ZuulProxyMarkerConfiguration.Marker();
}
class Marker {
Marker() {
}
}
}
在该类上面通过@ConditionalOnBean({Marker.class}) 注解导入,该类的实现原理ConditionalOnBean是通过BeanFactory
去获取到spring容器中是否该bean,如果没有直接放过,如果该类存在,然后将该类装载到spring容器中。
// 前置过滤器 prefiler
@Bean
@ConditionalOnMissingBean({PreDecorationFilter.class})
public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) {
return new PreDecorationFilter(routeLocator, this.server.getServlet().getContextPath(), this.zuulProperties, proxyRequestHelper);
}
// 负载均衡过滤器 router
@Bean
@ConditionalOnMissingBean({RibbonRoutingFilter.class})
public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper, RibbonCommandFactory<?> ribbonCommandFactory) {
RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory, this.requestCustomizers);
return filter;
}
// simpleHostRoutingFilter过滤器
@Bean
@ConditionalOnMissingBean({SimpleHostRoutingFilter.class, CloseableHttpClient.class})
public SimpleHostRoutingFilter simpleHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties zuulProperties, ApacheHttpClientConnectionManagerFactory connectionManagerFactory, ApacheHttpClientFactory httpClientFactory) {
return new SimpleHostRoutingFilter(helper, zuulProperties, connectionManagerFactory, httpClientFactory);
}
通过上面导航到他的父类,查看继续分析。 ConditionalOnMissingBean 上面已经做了介绍
@Bean
@ConditionalOnMissingBean(
name = {"zuulServlet"}
)
@ConditionalOnProperty(
name = {"zuul.use-filter"},
havingValue = "false",
matchIfMissing = true
)
public ServletRegistrationBean zuulServlet() {
ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean(new ZuulServlet(), new String[]{this.zuulProperties.getServletPattern()});
servlet.addInitParameter("buffer-requests", "false");
return servlet;
}
同是也注入了一些基于zuul的过滤器,表单等等,基本都是pre类型。
@Bean
@ConditionalOnMissingBean
public FormBodyWrapperFilter formBodyWrapperFilter() {
return new FormBodyWrapperFilter();
}
他还注入的基于zuul的过滤器。SendResponseFilter、Error类型 都是post类型。
@Bean
public SendResponseFilter sendResponseFilter(ZuulProperties properties) {
return new SendResponseFilter(this.zuulProperties);
}
继续初始化… FilterRegistry 从名字上猜测用于过滤器注册,主要存储一些ZuulFilter,采用ConcurrentHashMap作为容器。FilterLoader加载filter
@Configuration
protected static class ZuulFilterConfiguration {
@Autowired
private Map<String, ZuulFilter> filters;
protected ZuulFilterConfiguration() {
}
@Bean
public ZuulFilterInitializer zuulFilterInitializer(CounterFactory counterFactory, TracerFactory tracerFactory) {
// 加载
FilterLoader filterLoader = FilterLoader.getInstance();
// 注册
FilterRegistry filterRegistry = FilterRegistry.instance();
return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry);
}
}
这个类是用于定时加载filter如果该类以及注册过直接跳过,否则先编译class文件,然后在进行注册。
void startPoller() {
this.poller = new Thread("GroovyFilterFileManagerPoller") {
public void run() {
while(FilterFileManager.this.bRunning) {
try {
sleep((long)(FilterFileManager.this.pollingIntervalSeconds * 1000));
FilterFileManager.this.manageFiles();
} catch (Exception var2) {
var2.printStackTrace();
}
}
}
};
this.poller.setDaemon(true);
this.poller.start();
}
该类以及基本分析完成、接下来分析每一个细节ZuulServle核心组件,他是基于HttpServlet该的实现
servlet的生命周期… 从这段代码中我们可以看出来先执行preRoute、route、postRoute
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
try {
this.init((HttpServletRequest)servletRequest, (HttpServletResponse)servletResponse);
RequestContext context = RequestContext.getCurrentContext();
context.setZuulEngineRan();
try {
this.preRoute();
} catch (ZuulException var13) {
this.error(var13);
this.postRoute();
return;
}
try {
this.route();
} catch (ZuulException var12) {
this.error(var12);
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();
}
}
public void init(HttpServletRequest servletRequest, HttpServletResponse servletResponse) {
// 获取filter共享上下对象
RequestContext ctx = RequestContext.getCurrentContext();
if (this.bufferRequests) {
// 包装请求
ctx.setRequest(new HttpServletRequestWrapper(servletRequest));
} else {
ctx.setRequest(servletRequest);
}
ctx.setResponse(new HttpServletResponseWrapper(servletResponse));
}
最后通过遍历 pre --post router 都是一样…
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 = (ZuulFilter)list.get(i);
Object result = this.processZuulFilter(zuulFilter);
if (result != null && result instanceof Boolean) {
bResult |= (Boolean)result;
}
}
}
return bResult;
}