開發與維運

Spring Cloud Zuul 源碼解析

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 路由-源碼分析(待更新)

Leave a Reply

Your email address will not be published. Required fields are marked *