启动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 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 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
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 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
这两个类的初始化都是在ZuulServerAutoConfiguration这个自动装载的
@Configuration
protected static class ZuulFilterConfiguration {
@Autowired
private Map 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 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 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 fallbackProviderCache;
private FallbackProvider defaultFallbackProvider = null;
public AbstractRibbonCommandFactory(Set 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.emptySet());
}
public OkHttpRibbonCommandFactory(SpringClientFactory clientFactory,
ZuulProperties zuulProperties, Set 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 configKey, int defaultValue) {
DynamicPropertyFactory dynamicPropertyFactory = DynamicPropertyFactory
.getInstance();
return dynamicPropertyFactory
.getIntProperty(commandKey + "." + config.getNameSpace() + "." + property,
config.get(configKey, defaultValue))
.get();
}
当OkHttpRibbonCommand创建完成后, 这些数据就都设置完成了,