启动 zuul 网关模块
这里涉及了 spring 的注解驱动. 自动配置等相关知识
@EnableZuulProxy-> @import(ZuulProxyMarkerConfiguration.class)-> @Bean 就是初始化了 Marker 类. 相当于打标记
通过 Maker 类 找到了 zuul 的自动配置类 ZuulProxyAutoConfiguration 和父类 ZuulServerAutoConfiguration 并在 MATA-INF/spring.factories 里面找到了这两个类的配置项:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration,\
org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration
这两个类的加载都是通过 @EnableAutoConfiguration 完成的.
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 的执行顺序
- init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse); 初始化 ZuulRunner
- preRouting() -> zuulRunner.preRoute() -> FilterProcessor.getInstance().preRoute() -> runFilters(“pre”); pre 在请求路由之前执行. 业务上可以做一些验证之类的操作
- routing() -> zuulRunner.route(); -> FilterProcessor.getInstance().route() -> runFilters(“route”); route 路由请求时调用. 转发请求.
- postRouting() -> zuulRunner.postRoute(); -> FilterProcessor.getInstance().postRoute(); -> runFilters(“post”); post: 用来处理响应
- error(e) -> zuulRunner.error(); -> FilterProcessor.getInstance().error() -> runFilters(“error”); error 当错误发生时就会调用这个类型的 filter
ZuulRunner(运行器) 类 和 FilterProcessor(执行器) 类 真正的核心类
ZuulRunner 类的作用
- 调用 FilterProcessor
- 是否要使用 HttpServletRequest 的包装类 HttpServletRequestWrapper(拓展 extends javax.servlet.http.HttpServletRequestWrapper)
提供了一些 方便的 API. 比如 HashMap<String, String[]> getParameters() 等
FilterProcessor 类
首先是单例.
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 这个自动装载的
@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 托管, 就可以加载进来.
pre 过滤器
ServletDetectionFilter 检测当前请求是通过 Spring 的 DispatcherServlet 处理运行,还是通过 ZuulServlet 来处理运行
优先级 -3.
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 创建完成后, 这些数据就都设置完成了,