Spring Cloud Zuul 源码解析

 容器服务Docker K8S     |      2020-03-25 00:00:00

Zuul 架构图

Zuul的官方文档中的架构图
image.png
从架构图中可以看到 Zuul 通过Zuul Servlet 和 一系列 Zuul Filter 来完成智能路由和过滤器的功能。

Zuul 工作原理概述(转)

Zuul中,整个请求的过程是这样的,首先将请求给 ZuulServlet 处理,ZuulServlet中有一个ZuulRunner对象,该对象中初始化了RequestContext, RequestContext 作为整个请求的上下文,封装了请求的一些数据,并被所有的ZuulFilter共享。
ZuulRunner 中还有 FilterProcessorFilterProcessor作为执行所有的ZuulFilter的管理器。FilterProcessor FilterLoader 中获取ZuulFilter,而ZuulFilter是被FilterFileManager所加载,并支持groovy热加载,采用了轮询的方式热加载。
有了这些Filter之后,ZuulServlet首先执行的pre类型的过滤器,再执行route类型的过滤器,最后执行的是post 类型的过滤器。
如果在执行这些过滤器有错误的时候则会执行error类型的过滤器。执行完这些过滤器,最终将请求的结果返回给客户端。

Zuul 启动—源码分析

在程序的启动类上加@EnableZuulProxy 注解,我们可以使用Zuul 提供的功能了,该注解的源码为:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Import({ZuulProxyMarkerConfiguration.class})
public @interface EnableZuulProxy {
}

源码中,@EnableZuulProxy 引入了ZuulProxyMarkerConfiguration 配置类,跟踪ZuulProxyMarkerConfiguration 类:

public class ZuulProxyMarkerConfiguration {
    public ZuulProxyMarkerConfiguration() {
    }

    @Bean
    public ZuulProxyMarkerConfiguration.Marker zuulProxyMarkerBean() {
        return new ZuulProxyMarkerConfiguration.Marker();
    }

    class Marker {
        Marker() {
        }
    }
}

ZuulProxyMarkerConfiguration 配置类中,发现只是注册了一个ZuulProxyMarkerConfiguration.Markerbean。我们通过分析应该会有依赖这个bean的配置类。然后我们找到了 ZuulProxyAutoConfiguration 依赖了ZuulProxyMarkerConfiguration.Markerbean
跟踪 ZuulProxyAutoConfiguration

@Configuration
@Import({RestClientRibbonConfiguration.class, OkHttpRibbonConfiguration.class, HttpClientRibbonConfiguration.class, HttpClientConfiguration.class})
@ConditionalOnBean({Marker.class})
public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration {
  
    @Bean
    @ConditionalOnMissingBean({DiscoveryClientRouteLocator.class})
    public DiscoveryClientRouteLocator discoveryRouteLocator() {
        return new DiscoveryClientRouteLocator(this.server.getServlet().getContextPath(), this.discovery, this.zuulProperties, this.serviceRouteMapper, this.registration);
    }

    @Bean
    @ConditionalOnMissingBean({PreDecorationFilter.class})
    public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) {
        return new PreDecorationFilter(routeLocator, this.server.getServlet().getContextPath(), this.zuulProperties, proxyRequestHelper);
    }

    @Bean
    @ConditionalOnMissingBean({RibbonRoutingFilter.class})
    public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper, RibbonCommandFactory<?> ribbonCommandFactory) {
        RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory, this.requestCustomizers);
        return filter;
    }

    @Bean
    @ConditionalOnMissingBean({SimpleHostRoutingFilter.class, CloseableHttpClient.class})
    public SimpleHostRoutingFilter simpleHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties zuulProperties, ApacheHttpClientConnectionManagerFactory connectionManagerFactory, ApacheHttpClientFactory httpClientFactory) {
        return new SimpleHostRoutingFilter(helper, zuulProperties, connectionManagerFactory, httpClientFactory);
    }

    @Bean
    @ConditionalOnMissingBean({SimpleHostRoutingFilter.class})
    public SimpleHostRoutingFilter simpleHostRoutingFilter2(ProxyRequestHelper helper, ZuulProperties zuulProperties, CloseableHttpClient httpClient) {
        return new SimpleHostRoutingFilter(helper, zuulProperties, httpClient);
    }

    @Bean
    @ConditionalOnMissingBean({ServiceRouteMapper.class})
    public ServiceRouteMapper serviceRouteMapper() {
        return new SimpleServiceRouteMapper();
    }
}

我们发现在类ZuulProxyAutoConfiguration中,引入了RestClientRibbonConfiguration, OkHttpRibbonConfiguration, HttpClientRibbonConfiguration, HttpClientConfigurationZuul默认是用HttpClientRibbonConfiguration做负载均衡配置, 注入了DiscoveryClientRibbonConfiguration用作负载均衡相关。注入了一些列的Filter,
pre类型: PreDecorationFilter ; // 装饰 Request
route类型: RibbonRoutingFilter , SimpleHostRoutingFilter ; // 路由Filter
ZuulProxyAutoConfiguration 的父类ZuulServerAutoConfiguration中,也引入了一些配置信息:

@EnableConfigurationProperties({ZuulProperties.class})
@ConditionalOnClass({ZuulServlet.class, ZuulServletFilter.class})
@ConditionalOnBean({Marker.class})
public class ZuulServerAutoConfiguration {

    // 在缺失`ZuulServlet`的情况下注入`ZuulServlet`
    @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;
    }
    
    // 在缺失`ZuulServletFilter`的情况下注入`ZuulServletFilter`
    @Bean
    @ConditionalOnMissingBean(
        name = {"zuulServletFilter"}
    )
    @ConditionalOnProperty(
        name = {"zuul.use-filter"},
        havingValue = "true",
        matchIfMissing = false
    )
    public FilterRegistrationBean zuulServletFilter() {
        FilterRegistrationBean<ZuulServletFilter> filterRegistration = new FilterRegistrationBean();
        filterRegistration.setUrlPatterns(Collections.singleton(this.zuulProperties.getServletPattern()));
        filterRegistration.setFilter(new ZuulServletFilter());
        filterRegistration.setOrder(2147483647);
        filterRegistration.addInitParameter("buffer-requests", "false");
        return filterRegistration;
    }
    // 注入  `ServletDetectionFilter`
    @Bean
    public ServletDetectionFilter servletDetectionFilter() {
        return new ServletDetectionFilter();
    }

    // 注入  `FormBodyWrapperFilter`
    @Bean
    public FormBodyWrapperFilter formBodyWrapperFilter() {
        return new FormBodyWrapperFilter();
    }

    // 注入  `DebugFilter`
    @Bean
    public DebugFilter debugFilter() {
        return new DebugFilter();
    }

   // 注入  `Servlet30WrapperFilter`
    @Bean
    public Servlet30WrapperFilter servlet30WrapperFilter() {
        return new Servlet30WrapperFilter();
    }
    
  // 注入  `SendResponseFilter`
    @Bean
    public SendResponseFilter sendResponseFilter(ZuulProperties properties) {
        return new SendResponseFilter(this.zuulProperties);
    }

   // 注入  `SendErrorFilter`
    @Bean
    public SendErrorFilter sendErrorFilter() {
        return new SendErrorFilter();
    }
 
  // 注入  `SendForwardFilter`
    @Bean
    public SendForwardFilter sendForwardFilter() {
        return new SendForwardFilter();
    }
    
    
     @Configuration
    protected static class ZuulFilterConfiguration {
        @Autowired
        private Map<String, ZuulFilter> filters;

        protected ZuulFilterConfiguration() {
        }
       //  ZuulFilterInitializer,在初始化类中将Filter向FilterRegistry注册
        @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);
        }
    }
}

父类ZuulServerAutoConfiguration中,在缺失ZuulServletZuulServletFilterbean的情况下,注入ZuulServletZuulServletFilter。同时也注入了其他的过滤器,
pre类型: ServletDetectionFilterDebugFilterServlet30WrapperFilter ;
post类型: SendResponseFilter ; // 响应处理Filter
route类型: SendForwardFilter ; // 重定向处理Filter
error类型 : SendErrorFilter ; // 错误处理Filter

初始化ZuulFilterInitializer类,通过FilterLoader 将所有的FilterFilterRegistry注册。我们看一下ZuulFilterInitializer类中部分代码

public class ZuulFilterInitializer {
   
    // 初始化完成后注册所有的Filter
    @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());
        }

    }
    // 销毁前移除所有注册所有的Filter
    @PreDestroy
    public void contextDestroyed() {
        log.info("Stopping filter initializer");
        Iterator var1 = this.filters.entrySet().iterator();

        while(var1.hasNext()) {
            Entry<String, ZuulFilter> entry = (Entry)var1.next();
            this.filterRegistry.remove((String)entry.getKey());
        }

        this.clearLoaderCache();
        TracerFactory.initialize((TracerFactory)null);
        CounterFactory.initialize((CounterFactory)null);
    }
}

Zuul 路由-源码分析(待更新)