zuul網關源碼閱讀

啓動zuul網關模塊

這裏涉及了spring的註解驅動. 自動配置等相關知識
@EnableZuulProxy-> @import(ZuulProxyMarkerConfiguration.class)-> @Bean就是初始化了Marker類. 至關於打標記java

經過Maker類 找到了zuul的自動配置類ZuulProxyAutoConfiguration和父類ZuulServerAutoConfiguration 並在MATA-INF/spring.factories裏面找到了這兩個類的配置項:spring

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

這兩個類的加載都是經過@EnableAutoConfiguration完成的.segmentfault

ZuulServerAutoConfiguration配置類

@Configuration
//啓動zuul屬性. 能夠理解爲加載ZuulProperties
@EnableConfigurationProperties({ ZuulProperties.class })
//條件轉載. 須要依賴ZuulServlet和ZuulServletFilter類. 也就是說要依賴zuul-core
@ConditionalOnClass({ ZuulServlet.class, ZuulServletFilter.class })
//上下文環境中必須存在Marker這個Bean.
@ConditionalOnBean(ZuulServerMarkerConfiguration.Marker.class)
public class ZuulServerAutoConfiguration {


    @Bean
     // 缺乏zuulServlet Bean時加載
    @ConditionalOnMissingBean(name = "zuulServlet")
    // yml文件中配置的屬性zuul.use-filter = false或者沒有配置時加載
    @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")
    //yml文件中配置的屬性zuul.use-filter = true. 必需要有這個配置還必須是true 纔會加載.
    @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());
        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;
    }


}

ZuulServlet類和ZuulServletFilter類是zuul提供的兩種啓動方式, 對應了servlet和servlet Filter.設計模式

servlet指南

ZuulServletFilter

這個類告訴了zuul filter的執行順序app

  1. init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); 初始化ZuulRunner
  2. preRouting() -> zuulRunner.preRoute() -> FilterProcessor.getInstance().preRoute() -> runFilters("pre"); pre在請求路由以前執行. 業務上能夠作一些驗證之類的操做
  3. routing() -> zuulRunner.route(); -> FilterProcessor.getInstance().route() -> runFilters("route"); route 路由請求時調用. 轉發請求.
  4. postRouting() -> zuulRunner.postRoute(); -> FilterProcessor.getInstance().postRoute(); -> runFilters("post"); post: 用來處理響應
  5. error(e) -> zuulRunner.error(); -> FilterProcessor.getInstance().error() -> runFilters("error"); error 當錯誤發生時就會調用這個類型的filter

ZuulRunner(運行器)類 和 FilterProcessor(執行器)類 真正的核心類

ZuulRunner類的做用

  1. 調用FilterProcessor
  2. 是否要使用HttpServletRequest的包裝類HttpServletRequestWrapper(拓展 extends javax.servlet.http.HttpServletRequestWrapper)

提供了一些 方便的API. 好比 HashMap<String, String[]> getParameters()等負載均衡

FilterProcessor類

首先是單例.jsp

public class FilterProcessor {


 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 = list.get(i);
                Object result = processZuulFilter(zuulFilter);
                if (result != null && result instanceof Boolean) {
                    bResult |= ((Boolean) result);
                }
            }
        }
        return bResult;
    }
}

FilterLoader.getInstance().getFiltersByType(sType); 是獲取sType類型的filter. 並按照優先級進行排序.
其背後調用了FilterRegistry這個類 這個類很簡單, 維護了一個ConcurrentHashMap<String, ZuulFilter> filters 容器.
這兩個類的初始化都是在ZuulServerAutoConfiguration這個自動裝載的ide

@Configuration
    protected static class ZuulFilterConfiguration {

        @Autowired
        private Map<String, ZuulFilter> filters;

        @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);
        }

    }

這個filters屬性時如何初始化的. 業務本身定義的filter只要交給spring託管, 就能夠加載進來.post

pre過濾器

ServletDetectionFilter 檢測當前請求是經過Spring的DispatcherServlet處理運行,仍是經過ZuulServlet來處理運行

優先級 -3.ui

Servlet30WrapperFilter 將原始的HttpServletRequest包裝成Servlet30RequestWrapper對象

優先級 -2

FormBodyWrapperFilter 將符合條件的請求包裝成FormBodyRequestWrapper對象

優先級 -1

執行條件: application/x-www-form-urlencoded 或者 multipart/form-data 時候執行

DebugFilter 將當前RequestContext中的debugRouting和debugRequest參數設置爲true

優先級 1

執行條件: 請求中的debug參數(該參數能夠經過zuul.debug.parameter來自定義)爲true,或者配置參數zuul.debug.request爲true時執行

PreDecorationFilter

優先級 5

執行條件: RequestContext不存在forward.to和serviceId兩個參數時執行

public class PreDecorationFilter extends ZuulFilter {
@Override
    public Object run() {
//獲取請求上下文
        RequestContext ctx = RequestContext.getCurrentContext();
//獲取請求路徑
        final String requestURI = this.urlPathHelper
                .getPathWithinApplication(ctx.getRequest());
//獲取路由信息(CompositeRouteLocator 實在自動裝配階段裝配的)
        Route route = this.routeLocator.getMatchingRoute(requestURI);
// 路由存在
        if (route != null) {
//獲取路由的定位信息(url或者serviceId)
            String location = route.getLocation();
            if (location != null) {
//設置requestURI= path
                ctx.put(REQUEST_URI_KEY, route.getPath());
//設置proxy = routeId
                ctx.put(PROXY_KEY, route.getId());
//不存在自定義的敏感頭信息 設置默認的 ("Cookie", "Set-Cookie", "Authorization")
                if (!route.isCustomSensitiveHeaders()) {
                    this.proxyRequestHelper.addIgnoredHeaders(
                            this.properties.getSensitiveHeaders().toArray(new String[0]));
                }
//存在 就用用戶本身定義的
                else {
                    this.proxyRequestHelper.addIgnoredHeaders(
                            route.getSensitiveHeaders().toArray(new String[0]));
                }
//設置重試屬性
                if (route.getRetryable() != null) {
                    ctx.put(RETRYABLE_KEY, route.getRetryable());
                }
//若是location以http或https開頭,將其添加到RequestContext的routeHost中,在RequestContext的originResponseHeaders中添加X-Zuul-Service與location的鍵值對;
                if (location.startsWith(HTTP_SCHEME + ":")
                        || location.startsWith(HTTPS_SCHEME + ":")) {
                    ctx.setRouteHost(getUrl(location));
                    ctx.addOriginResponseHeader(SERVICE_HEADER, location);
                }
//若是location以forward:開頭,則將其添加到RequestContext的forward.to中,將RequestContext的routeHost設置爲null並返回;
                else if (location.startsWith(FORWARD_LOCATION_PREFIX)) {
                    ctx.set(FORWARD_TO_KEY,
                            StringUtils.cleanPath(
                                    location.substring(FORWARD_LOCATION_PREFIX.length())
                                            + route.getPath()));
                    ctx.setRouteHost(null);
                    return null;
                }
//不然將location添加到RequestContext的serviceId中,將RequestContext的routeHost設置爲null,在RequestContext的originResponseHeaders中添加X-Zuul-ServiceId與location的鍵值對。
                else {
                    // set serviceId for use in filters.route.RibbonRequest
                    ctx.set(SERVICE_ID_KEY, location);
                    ctx.setRouteHost(null);
                    ctx.addOriginResponseHeader(SERVICE_ID_HEADER, location);
                }
//若是zuul.addProxyHeaders=true 則在RequestContext的zuulRequestHeaders中添加一系列請求頭:X-Forwarded-Host、X-Forwarded-Port、X-Forwarded-Proto、X-Forwarded-Prefix、X-Forwarded-For
                if (this.properties.isAddProxyHeaders()) {
                    addProxyHeaders(ctx, route);
                    String xforwardedfor = ctx.getRequest()
                            .getHeader(X_FORWARDED_FOR_HEADER);
                    String remoteAddr = ctx.getRequest().getRemoteAddr();
                    if (xforwardedfor == null) {
                        xforwardedfor = remoteAddr;
                    }
                    else if (!xforwardedfor.contains(remoteAddr)) { // Prevent duplicates
                        xforwardedfor += ", " + remoteAddr;
                    }
                    ctx.addZuulRequestHeader(X_FORWARDED_FOR_HEADER, xforwardedfor);
                }
//若是zuul.addHostHeader=ture 則在則在RequestContext的zuulRequestHeaders中添加host
                if (this.properties.isAddHostHeader()) {
                    ctx.addZuulRequestHeader(HttpHeaders.HOST,
                            toHostHeader(ctx.getRequest()));
                }
            }
        }
//若是 route=null 在RequestContext中將forward.to設置爲forwardURI,默認狀況下forwardURI爲請求路徑。              
        else {
            log.warn("No route found for uri: " + requestURI);
            String forwardURI = getForwardUri(requestURI);

            ctx.set(FORWARD_TO_KEY, forwardURI);
        }
        return null;
    }
}

route過濾器

RibbonRoutingFilter 使用Ribbon和Hystrix來向服務實例發起請求,並將服務實例的請求結果返回

優先級 10

執行條件: RequestContext中的routeHost爲null,serviceId不爲null。sendZuulResponse=true. 即只對經過serviceId配置路由規則的請求生效

使用Ribbon和Hystrix來向服務實例發起請求,並將服務實例的請求結果返回

SimpleHostRoutingFilter

優先級 100

執行條件: RequestContext中的routeHost不爲null。即只對經過url配置路由規則的請求生效

直接向routeHost參數的物理地址發起請求,該請求是直接經過httpclient包實現的,而沒有使用Hystrix命令進行包裝,因此這類請求並無線程隔離和熔斷器的保護。

SendForwardFilter 獲取forward.to中保存的跳轉地址,跳轉過去

優先級 500

執行條件: RequestContext中的forward.to不爲null。即用來處理路由規則中的forward本地跳轉配置

post過濾器

SendResponseFilter 在請求響應中增長頭信息(根據設置有X-Zuul-Debug-Header、Date、Content-Type、Content-Length等):addResponseHeaders;發送響應內容:writeResponse。

優先級 1000

執行條件: 沒有拋出異常,RequestContext中的throwable屬性爲null(若是不爲null說明已經被error過濾器處理過了,這裏的post過濾器就不須要處理了),而且RequestContext中zuulResponseHeaders、responseDataStream、responseBody三者有同樣不爲null(說明實際請求的響應不爲空)。

LocationRewriteFilter

優先級 SendResponseFilter - 100

執行條件: HttpStatus.valueOf(statusCode).is3xxRedirection() 響應碼是3XX的時候執行

功能: 將Location信息轉化爲Zuul URL.

error過濾器

SendErrorFilter

優先級 0

執行條件:RequestContext中的throwable不爲null,且sendErrorFilter.ran屬性爲false。

在request中設置javax.servlet.error.status_code、javax.servlet.error.exception、javax.servlet.error.message三個屬性。將RequestContext中的sendErrorFilter.ran屬性設置爲true。而後組織成一個forward到API網關/error錯誤端點的請求來產生錯誤響應。

Ribbon和Hystrix

ZuulProxyAutoConfiguration配置類

@Configuration
//加載這個4個類
@Import({ RibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class,
        RibbonCommandFactoryConfiguration.OkHttpRibbonConfiguration.class,
        RibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class,
        HttpClientConfiguration.class })
@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class)
public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(RibbonRoutingFilter.class)
    public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper,
            RibbonCommandFactory<?> ribbonCommandFactory) {
        //ribbonCommandFactory這個具體是什麼類型 取決import導入的類
        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);
    }
}

ZuulProxyAutoConfiguration自動配置類.

是ZuulServerAutoConfiguration的子類, 導入了 RestClientRibbonConfiguration OkHttpRibbonConfiguration HttpClientRibbonConfiguration三個自動配置.

SpringClientFactory
zuulProperties zuul的配置項
zuulFallbackProviders Hystrix回調

在RibbonRoutingFilter看到了zuul在何時啓動ribbon的. 同時出現了RibbonCommand類. 這是實現了HystrixExecutable. 這個類是能夠理解爲Hystrix的執行器.
RibbonCommand有四個子類. 一個抽象類AbstractRibbonCommand和三個實現類 分別是依據httpClient實現的和OkHttp實現的以及RestClient實現的.

RibbonCommand建立

這裏使用了設計模式抽象工廠方法模式. RibbonCommandFactory工廠類接口 AbstractRibbonCommandFactory抽象類. 功能是記錄FallbackProvider. 至關於註冊表.用map記錄.
三種RibbonCommand建立都有各自工廠去構建.

三種工廠類的構建

RibbonCommandFactoryConfiguration 工廠類自動配置
// 以okHttp爲例子
public class RibbonCommandFactoryConfiguration {

            @Target({ ElementType.TYPE, ElementType.METHOD })
            @Retention(RetentionPolicy.RUNTIME)
            @Documented
            @Conditional(OnRibbonOkHttpClientCondition.class)
            @interface ConditionalOnRibbonOkHttpClient {
        
            }



        @Configuration
        // ribbon.okhttp.enabled yml文件中存在這個屬性
        @ConditionalOnRibbonOkHttpClient
        // 環境中存在這個類okhttp3.OkHttpClient
        @ConditionalOnClass(name = "okhttp3.OkHttpClient")
        protected static class OkHttpRibbonConfiguration {
    
            @Autowired(required = false)
            //FallbackProvider的全部實現類 必須添加註解@Component. 在這裏能夠組裝完成.
            private Set<FallbackProvider> zuulFallbackProviders = Collections.emptySet();
            // @Bean 註冊到Spring IOC容器中.
            @Bean
            @ConditionalOnMissingBean
            public RibbonCommandFactory<?> ribbonCommandFactory(
                    SpringClientFactory clientFactory, ZuulProperties zuulProperties) {
                return new OkHttpRibbonCommandFactory(clientFactory, zuulProperties,
                        zuulFallbackProviders);
            }
    
        }

    private static class OnRibbonOkHttpClientCondition extends AnyNestedCondition {

        OnRibbonOkHttpClientCondition() {
            super(ConfigurationPhase.PARSE_CONFIGURATION);
        }

        @ConditionalOnProperty("ribbon.okhttp.enabled")
        static class RibbonProperty {

        }

    }
}

其餘的實現也是相同的套路.

ribbon.restclient.enabled 使用RestClientRibbonCommandFactory
ribbon.okhttp.enabled 使用OkHttpRibbonCommandFactory
ribbon.httpclient.enabled matchIfMissing=true 意思是當不設置任何值的時候,默認初始HttpClientRibbonCommandFactory

在結合ZuulProxyAutoConfiguration類中@Bean RibbonRoutingFilter的構建. 在項目啓動完成後,
RibbonRoutingFilter經過RibbonCommandFactory.create()方法. 是能夠構建出RibbonCommand類的.

RibbonRoutingFilter 過濾器
protected ClientHttpResponse forward(RibbonCommandContext context) throws Exception {
        Map<String, Object> info = this.helper.debug(context.getMethod(),
                context.getUri(), context.getHeaders(), context.getParams(),
                context.getRequestEntity());
        // 這裏的邏輯就清楚了.
        RibbonCommand command = this.ribbonCommandFactory.create(context);
        try {
            ClientHttpResponse response = command.execute();
            this.helper.appendDebug(info, response.getRawStatusCode(),
                    response.getHeaders());
            return response;
        }
        catch (HystrixRuntimeException ex) {
            return handleException(info, ex);
        }

    }
AbstractRibbonCommand類
  • OkHttpRibbonCommandFactory的構建

super(zuulFallbackProviders); -> AbstractRibbonCommandFactory()

public abstract class AbstractRibbonCommandFactory implements RibbonCommandFactory {

    private Map<String, FallbackProvider> fallbackProviderCache;

    private FallbackProvider defaultFallbackProvider = null;

    public AbstractRibbonCommandFactory(Set<FallbackProvider> fallbackProviders) {
        this.fallbackProviderCache = new HashMap<>();
        for (FallbackProvider provider : fallbackProviders) {
            String route = provider.getRoute();
            // 若是route設置的是* 或者 不設置.  就將這個FallbackProvider設置爲默認的
            if ("*".equals(route) || route == null) {
                defaultFallbackProvider = provider;
            }
            // 其餘的按照route值 註冊到map中.
            else {
                fallbackProviderCache.put(route, provider);
            }
        }
    }

    protected FallbackProvider getFallbackProvider(String route) {
        // 獲取的時候 若是在map中不存在. 就使用默認的
        FallbackProvider provider = fallbackProviderCache.get(route);
        if (provider == null) {
            provider = defaultFallbackProvider;
        }
        return provider;
    }

}
  • OkHttpRibbonCommandFactory#create()方法 雜糅了不少類的關鍵方法.
public class OkHttpRibbonCommandFactory extends AbstractRibbonCommandFactory {

    private SpringClientFactory clientFactory;

    private ZuulProperties zuulProperties;

    public OkHttpRibbonCommandFactory(SpringClientFactory clientFactory,
            ZuulProperties zuulProperties) {
        this(clientFactory, zuulProperties, Collections.<FallbackProvider>emptySet());
    }

    public OkHttpRibbonCommandFactory(SpringClientFactory clientFactory,
            ZuulProperties zuulProperties, Set<FallbackProvider> zuulFallbackProviders) {
        super(zuulFallbackProviders);
        this.clientFactory = clientFactory;
        this.zuulProperties = zuulProperties;
    }
@Override
    public OkHttpRibbonCommand create(final RibbonCommandContext context) {
//這個不解釋
        final String serviceId = context.getServiceId();
//依據服務ID得到FallbackProvider
        FallbackProvider fallbackProvider = getFallbackProvider(serviceId);
//建立負載均衡客戶端
        final OkHttpLoadBalancingClient client = this.clientFactory.getClient(serviceId,
                OkHttpLoadBalancingClient.class);
// 設置負載均衡
        client.setLoadBalancer(this.clientFactory.getLoadBalancer(serviceId));
//建立OkHttpRibbonCommand實例,
        return new OkHttpRibbonCommand(serviceId, client, context, zuulProperties,
                fallbackProvider, clientFactory.getClientConfig(serviceId));
    }
 }   
    public OkHttpRibbonCommand(final String commandKey,
            final OkHttpLoadBalancingClient client, final RibbonCommandContext context,
            final ZuulProperties zuulProperties,
            final FallbackProvider zuulFallbackProvider, final IClientConfig config) {
        //調用父類的構造方法
        super(commandKey, client, context, zuulProperties, zuulFallbackProvider, config);
    }

    public AbstractRibbonCommand(String commandKey, LBC client,
            RibbonCommandContext context, ZuulProperties zuulProperties,
            FallbackProvider fallbackProvider, IClientConfig config) {
        //getSetter 設置Hystrix的屬性值
        this(getSetter(commandKey, zuulProperties, config), client, context,
                fallbackProvider, config);
    }

    protected static Setter getSetter(final String commandKey,
            ZuulProperties zuulProperties, IClientConfig config) {

        // @formatter:off commandKey= serviceId 每一個CommandKey表明一個依賴抽象,相同的依賴要使用相同的CommandKey名稱。依賴隔離的根本就是對相同CommandKey的依賴作隔離.
        //CommandGroup 命令分組用於對依賴操做分組,便於統計,彙總等.
        Setter commandSetter = Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("RibbonCommand"))
                                .andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
        // 構建了策略和超時時間
        final HystrixCommandProperties.Setter setter = createSetter(config, commandKey, zuulProperties);
        //信號量方式
        if (zuulProperties.getRibbonIsolationStrategy() == ExecutionIsolationStrategy.SEMAPHORE) {
            final String name = ZuulConstants.ZUUL_EUREKA + commandKey + ".semaphore.maxSemaphores";
            // we want to default to semaphore-isolation since this wraps
            // 2 others commands that are already thread isolated
            // 獲取信號量大小 默認值100
            final DynamicIntProperty value = DynamicPropertyFactory.getInstance()
                    .getIntProperty(name, zuulProperties.getSemaphore().getMaxSemaphores());
            setter.withExecutionIsolationSemaphoreMaxConcurrentRequests(value.get());
        }
        //線程池方式
        else if (zuulProperties.getThreadPool().isUseSeparateThreadPools()) {
            //每一個serviceId一個線程池
            final String threadPoolKey = zuulProperties.getThreadPool().getThreadPoolKeyPrefix() + commandKey;
            commandSetter.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(threadPoolKey));
        }
        return commandSetter.andCommandPropertiesDefaults(setter);
        // @formatter:on
    }

    protected static HystrixCommandProperties.Setter createSetter(IClientConfig config,
            String commandKey, ZuulProperties zuulProperties) {
    //設置Hystrix超時時間
        int hystrixTimeout = getHystrixTimeout(config, commandKey);
    //設置策略 ribbon的默認策略是信息量
        return HystrixCommandProperties.Setter()
                .withExecutionIsolationStrategy(
                        zuulProperties.getRibbonIsolationStrategy())
                .withExecutionTimeoutInMilliseconds(hystrixTimeout);
    }

protected static int getHystrixTimeout(IClientConfig config, String commandKey) {
//獲取Ribbon的超時時間
        int ribbonTimeout = getRibbonTimeout(config, commandKey);
        DynamicPropertyFactory dynamicPropertyFactory = DynamicPropertyFactory
                .getInstance();
// 默認的超時時間
        int defaultHystrixTimeout = dynamicPropertyFactory.getIntProperty(
                "hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds",
                0).get();
// 獲取針對serviceId設置的超時時間
        int commandHystrixTimeout = dynamicPropertyFactory
                .getIntProperty("hystrix.command." + commandKey
                        + ".execution.isolation.thread.timeoutInMilliseconds", 0)
                .get();
        int hystrixTimeout;
// 若是設置了serverId的超時時間   就用serverId
        if (commandHystrixTimeout > 0) {
            hystrixTimeout = commandHystrixTimeout;
        }
// 不然查看默認的超時時間
        else if (defaultHystrixTimeout > 0) {
            hystrixTimeout = defaultHystrixTimeout;
        }
// 若是最後都沒有設置, 就用ribbon的
        else {
            hystrixTimeout = ribbonTimeout;
        }
// 能夠理解爲 設置了用serviceId的用serverid的,不然用Hystrix默認的.若是都沒設置用ribbon設置的
        if (hystrixTimeout < ribbonTimeout) {
            LOGGER.warn("The Hystrix timeout of " + hystrixTimeout + "ms for the command "
                    + commandKey
                    + " is set lower than the combination of the Ribbon read and connect timeout, "
                    + ribbonTimeout + "ms.");
        }
        return hystrixTimeout;
    }

    protected static int getRibbonTimeout(IClientConfig config, String commandKey) {
        int ribbonTimeout;
        //如何用戶沒有自定義使用系統默認的 2000ms
        if (config == null) {
            ribbonTimeout = RibbonClientConfiguration.DEFAULT_READ_TIMEOUT
                    + RibbonClientConfiguration.DEFAULT_CONNECT_TIMEOUT;
        }
        //讀取用戶設置的
        else {
            int ribbonReadTimeout = getTimeout(config, commandKey, "ReadTimeout",
                    IClientConfigKey.Keys.ReadTimeout,
                    RibbonClientConfiguration.DEFAULT_READ_TIMEOUT);
            int ribbonConnectTimeout = getTimeout(config, commandKey, "ConnectTimeout",
                    IClientConfigKey.Keys.ConnectTimeout,
                    RibbonClientConfiguration.DEFAULT_CONNECT_TIMEOUT);
            int maxAutoRetries = getTimeout(config, commandKey, "MaxAutoRetries",
                    IClientConfigKey.Keys.MaxAutoRetries,
                    DefaultClientConfigImpl.DEFAULT_MAX_AUTO_RETRIES);
            int maxAutoRetriesNextServer = getTimeout(config, commandKey,
                    "MaxAutoRetriesNextServer",
                    IClientConfigKey.Keys.MaxAutoRetriesNextServer,
                    DefaultClientConfigImpl.DEFAULT_MAX_AUTO_RETRIES_NEXT_SERVER);

            ribbonTimeout = (ribbonReadTimeout + ribbonConnectTimeout)
                    * (maxAutoRetries + 1) * (maxAutoRetriesNextServer + 1);
        }
        return ribbonTimeout;
    }

    private static int getTimeout(IClientConfig config, String commandKey,
            String property, IClientConfigKey<Integer> configKey, int defaultValue) {
        DynamicPropertyFactory dynamicPropertyFactory = DynamicPropertyFactory
                .getInstance();
        return dynamicPropertyFactory
                .getIntProperty(commandKey + "." + config.getNameSpace() + "." + property,
                        config.get(configKey, defaultValue))
                .get();
    }

當OkHttpRibbonCommand建立完成後, 這些數據就都設置完成了,

相關文章
相關標籤/搜索