服务网关Zuul的核心源码解析
在Zuul中, 整个请求的过程是这样的,首先将请求给zuulservlet处理,zuulservlet中有一个zuulRunner对象,该对象中初始化了RequestContext:作为存储整个请求的一些数据,并被所有的zuulfifilter共享。zuulRunner中还有 FilterProcessor,FilterProcessor作为执行所有的zuulfifilter的管理器。FilterProcessor从fifilterloader 中获取zuulfifilter,而zuulfifilter是被fifilterFileManager所加载,并支持groovy热加载,采用了轮询的方式热加载。有了这些fifilter之后,zuulservelet首先执行的Pre类型的 过滤器,再执行route类型的过滤器,最后执行的是post 类型的过滤器,如果在执行这些过滤器有错误的时候则会执行error类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。
(1)初始化
SpringCloud对Zuul的封装使得发布一个ZuulServer无比简单,根据自动装载原则可以在 spring-cloud-netflix-zuul-2.1.0.RELEASE.jar 下找到 spring.factories
ZuulServerAutoConfiguration,ZuulProxyAutoConfiguration 是Zuul服务端的自动配置类,这些配置类究竟负责什么工作,我们继续来看
@Configuration @Import({RestClientRibbonConfiguration.class, OkHttpRibbonConfiguration.class, HttpClientRibbonConfiguration.class, HttpClientConfiguration.class}) @ConditionalOnBean({Marker.class}) public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration { //省略 }
ZuulProxyAutoConfiguration 继承了 ZuulServerAutoConfiguration ,我们先看下这个配置类
@Configuration @EnableConfigurationProperties({ZuulProperties.class}) @ConditionalOnClass({ZuulServlet.class, ZuulServletFilter.class}) @ConditionalOnBean({Marker.class}) public class ZuulServerAutoConfiguration { @Bean @Primary public CompositeRouteLocator primaryRouteLocator(Collection<RouteLocator> routeLocators) { return new CompositeRouteLocator(routeLocators); } @Bean @ConditionalOnMissingBean({SimpleRouteLocator.class}) public SimpleRouteLocator simpleRouteLocator() { return new SimpleRouteLocator(this.server.getServlet().getContextPath(), this.zuulProperties); } @Bean public ZuulController zuulController() { return new ZuulController(); } @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); } } //其他省略 }
整理一下这里配置类里面做了哪些事情呢?
CompositeRouteLocator:组合路由定位器,看入参就知道应该是会保存好多个RouteLocator,构造过程中其实仅包括一个DiscoveryClientRouteLocator。
SimpleRouteLocator:默认的路由定位器,主要负责维护配置文件中的路由配置。
ZuulController:Zuul创建的一个Controller,用于将请求交由ZuulServlet处理。
ZuulHandlerMapping:这个会添加到SpringMvc的HandlerMapping链中,只有选择了ZuulHandlerMapping的请求才能出发到Zuul的后续流程。
注册ZuulFilterInitializer: 通过FilterLoader加载应用中所有的过滤器并将过滤器注册到FilterRegistry,那我们接下来一起看下过滤器是如何被加载到应用中的
public class ZuulFilterInitializer { private static final Log log = LogFactory.getLog(ZuulFilterInitializer.class); private final Map<String, ZuulFilter> filters; private final CounterFactory counterFactory; private final TracerFactory tracerFactory; private final FilterLoader filterLoader; private final FilterRegistry filterRegistry; public ZuulFilterInitializer(Map<String, ZuulFilter> filters, CounterFactory counterFactory, TracerFactory tracerFactory, FilterLoader filterLoader, FilterRegistry filterRegistry) { this.filters = filters; this.counterFactory = counterFactory; this.tracerFactory = tracerFactory; this.filterLoader = filterLoader; this.filterRegistry = filterRegistry; } @PostConstruct public void contextInitialized() { log.info("Starting filter initializer"); TracerFactory.initialize(this.tracerFactory); CounterFactory.initialize(this.counterFactory); Iterator var1 = this.filters.entrySet().iterator(); while(var1.hasNext()) { Entry<String, ZuulFilter> entry = (Entry)var1.next(); this.filterRegistry.put((String)entry.getKey(), (ZuulFilter)entry.getValue()); } }
(2)请求转发
在Zuul的自动配置中我们看到了 ZuulHandlerMapping ,为SpringMVC中 HandlerMapping 的拓展实现,会自动的添加到HandlerMapping链中。
public class ZuulHandlerMapping extends AbstractUrlHandlerMapping { private final RouteLocator routeLocator; private final ZuulController zuul; private ErrorController errorController; private PathMatcher pathMatcher = new AntPathMatcher(); private volatile boolean dirty = true; public ZuulHandlerMapping(RouteLocator routeLocator, ZuulController zuul) { this.routeLocator = routeLocator; this.zuul = zuul; this.setOrder(-200); } private void registerHandlers() { Collection<Route> routes = this.routeLocator.getRoutes(); if (routes.isEmpty()) { this.logger.warn("No routes found from RouteLocator"); } else { Iterator var2 = routes.iterator(); while(var2.hasNext()) { Route route = (Route)var2.next(); this.registerHandler(route.getFullPath(), this.zuul); } } } }
其主要目的就是把所有路径的请求导入到ZuulController上.另外的功效是当觉察RouteLocator路由表变更,则更新自己dirty状态,重新注册所有Route到ZuulController。
public class ZuulController extends ServletWrappingController { public ZuulController() { //在这里已经设置了ZuulServlet this.setServletClass(ZuulServlet.class); this.setServletName("zuul"); this.setSupportedMethods((String[])null); } public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView var3; try { //在这里面会调用ZuulServlet的service方法 var3 = super.handleRequestInternal(request, response); } finally { RequestContext.getCurrentContext().unset(); } return var3; } }
在 ZuulController 中的 handleRequest 方法,会调用已经注册的 ZuulServlet 完成业务请求,我们进入 ZuulServlet 看下内部是如何处理的
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(); } }
(3)过滤器
Zuul默认注入的过滤器可以在 spring-cloud-netflix-core.jar 中找到。