Hystrix的源码需要有一定基础rxjava,所以接下来的源码分析会很简单,因为作者只是想了解下Hystrix整个流程,对rxjava不熟悉。
Feign已经整合了Hystrix,那里面是如何工作的呢?配置文件中feign.hystrix.enabled=true,那我们为什么需要这个配置呢?
首先我们看下FeignClientsConfiguration,这个文件加载的时候,里面的bean也会相应的加载到容器中,其中有一个Bean时Builder
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({HystrixCommand.class, HystrixFeign.class})
protected static class HystrixFeignConfiguration {
protected HystrixFeignConfiguration() {
}
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
@ConditionalOnProperty(
name = {"feign.hystrix.enabled"}
)
public Builder feignHystrixBuilder() {
return HystrixFeign.builder();
}
}
开启了Hystrix,Builder的Bean类则会是HystrixFeign而就不是Feign了。有了HystrixFeign这个类,我们可以查到FeignAutoConfiguration类中
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass(
name = {"feign.hystrix.HystrixFeign"}
)
protected static class HystrixFeignTargeterConfiguration {
protected HystrixFeignTargeterConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public Targeter feignTargeter() {
return new HystrixTargeter();
}
}
生成HystrixTargeter类,调用FeignClientFactoryBean类中getObject的方法时,Builder和Target对象就是之前说的两个。
public T target(FeignClientFactoryBean factory, Builder feign, FeignContext context, HardCodedTarget target) {
if (!(feign instanceof feign.hystrix.HystrixFeign.Builder)) {
return feign.target(target);
} else {
feign.hystrix.HystrixFeign.Builder builder = (feign.hystrix.HystrixFeign.Builder)feign;
String name = StringUtils.isEmpty(factory.getContextId()) ? factory.getName() : factory.getContextId();
SetterFactory setterFactory = (SetterFactory)this.getOptional(name, context, SetterFactory.class);
if (setterFactory != null) {
builder.setterFactory(setterFactory);
}
Class> fallback = factory.getFallback();
if (fallback != Void.TYPE) {
return this.targetWithFallback(name, context, target, builder, fallback);
} else {
Class> fallbackFactory = factory.getFallbackFactory();
return fallbackFactory != Void.TYPE ? this.targetWithFallbackFactory(name, context, target, builder, fallbackFactory) : feign.target(target);
}
}
}
HystrixTargeter.target核心方法,先加载fallback,没有则加载fallbackFactory,这个可以说明fallback的优先级高。接下来查看targetwithFallback方法
Feign build(final FallbackFactory> nullableFallbackFactory) {
super.invocationHandlerFactory(new InvocationHandlerFactory() {
public InvocationHandler create(Target target, Map dispatch) {
return new HystrixInvocationHandler(target, dispatch, Builder.this.setterFactory, nullableFallbackFactory);
}
});
super.contract(new HystrixDelegatingContract(this.contract));
return super.build();
}
生成HystrixInvocationHandler实例,并且执行父类的build().
public Feign build() {
Factory synchronousMethodHandlerFactory = new Factory(this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, this.decode404, this.closeAfterDecode, this.propagationPolicy);
ParseHandlersByName handlersByName = new ParseHandlersByName(this.contract, this.options, this.encoder, this.decoder, this.queryMapEncoder, this.errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, this.invocationHandlerFactory, this.queryMapEncoder);
}
赋值,生成ReflectiveFeign执行其newInstance方法。接下来和Fiegn流程差不多,但是需要注意的是,调用提供者的时候HystrixInvocationHandler会先拦截其动作,调用其invoke方法
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
if (!"equals".equals(method.getName())) {
if ("hashCode".equals(method.getName())) {
return this.hashCode();
} else if ("toString".equals(method.getName())) {
return this.toString();
} else {
HystrixCommand
这个类便为我们提供了Hystrix的实现。生成的实例HystrixCommand,该实例初始化线程池,熔断器和其他配置等
protected AbstractCommand(HystrixCommandGroupKey group, HystrixCommandKey key, HystrixThreadPoolKey threadPoolKey, HystrixCircuitBreaker circuitBreaker, HystrixThreadPool threadPool, Setter commandPropertiesDefaults, com.netflix.hystrix.HystrixThreadPoolProperties.Setter threadPoolPropertiesDefaults, HystrixCommandMetrics metrics, AbstractCommand.TryableSemaphore fallbackSemaphore, AbstractCommand.TryableSemaphore executionSemaphore, HystrixPropertiesStrategy propertiesStrategy, HystrixCommandExecutionHook executionHook) {
this.commandState = new AtomicReference(AbstractCommand.CommandState.NOT_STARTED);
this.threadState = new AtomicReference(AbstractCommand.ThreadState.NOT_USING_THREAD);
this.executionResult = ExecutionResult.EMPTY;
this.isResponseFromCache = false;
this.commandStartTimestamp = -1L;
this.isCommandTimedOut = new AtomicReference(AbstractCommand.TimedOutStatus.NOT_EXECUTED);
this.commandGroup = initGroupKey(group);
this.commandKey = initCommandKey(key, this.getClass());
this.properties = initCommandProperties(this.commandKey, propertiesStrategy, commandPropertiesDefaults);
this.threadPoolKey = initThreadPoolKey(threadPoolKey, this.commandGroup, (String)this.properties.executionIsolationThreadPoolKeyOverride().get());
this.metrics = initMetrics(metrics, this.commandGroup, this.threadPoolKey, this.commandKey, this.properties);
this.circuitBreaker = initCircuitBreaker((Boolean)this.properties.circuitBreakerEnabled().get(), circuitBreaker, this.commandGroup, this.commandKey, this.properties, this.metrics);
this.threadPool = initThreadPool(threadPool, this.threadPoolKey, threadPoolPropertiesDefaults);
this.eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
this.concurrencyStrategy = HystrixPlugins.getInstance().getConcurrencyStrategy();
HystrixMetricsPublisherFactory.createOrRetrievePublisherForCommand(this.commandKey, this.commandGroup, this.metrics, this.circuitBreaker, this.properties);
this.executionHook = initExecutionHook(executionHook);
this.requestCache = HystrixRequestCache.getInstance(this.commandKey, this.concurrencyStrategy);
this.currentRequestLog = initRequestLog((Boolean)this.properties.requestLogEnabled().get(), this.concurrencyStrategy);
this.fallbackSemaphoreOverride = fallbackSemaphore;
this.executionSemaphoreOverride = executionSemaphore;
}
每次调用的时候,只有再第一次调用的时候才会创建资源,以HystrixThreadPool为例
static HystrixThreadPool getInstance(HystrixThreadPoolKey threadPoolKey, Setter propertiesBuilder) {
String key = threadPoolKey.name();
HystrixThreadPool previouslyCached = (HystrixThreadPool)threadPools.get(key);
if (previouslyCached != null) {
return previouslyCached;
} else {
Class var4 = HystrixThreadPool.class;
synchronized(HystrixThreadPool.class) {
if (!threadPools.containsKey(key)) {
threadPools.put(key, new HystrixThreadPool.HystrixThreadPoolDefault(threadPoolKey, propertiesBuilder));
}
}
return (HystrixThreadPool)threadPools.get(key);
}
}
static final ConcurrentHashMapthreadPools = new ConcurrentHashMap();
如果threadPools里面没有则新建,有的话则从pools中拿出来。
初始化之后,执行excute,
public R execute() {
try {
return this.queue().get();
} catch (Exception var2) {
throw Exceptions.sneakyThrow(this.decomposeException(var2));
}
}
该方法是同步,调用后直接阻塞,直到依赖服务返回单条结果,或抛异常。继续调用queue方法,queue的方法是异步,该command在线程池上排队,并在完成后返回一个 Future 以获取结果。无论是哪种执行command的方式,最终都是依赖toObservable().
关注一下applyHystrixSemantics方法
private Observable applyHystrixSemantics(AbstractCommand _cmd) {
this.executionHook.onStart(_cmd);
if (this.circuitBreaker.allowRequest()) {
final AbstractCommand.TryableSemaphore executionSemaphore = this.getExecutionSemaphore();
final AtomicBoolean semaphoreHasBeenReleased = new AtomicBoolean(false);
Action0 singleSemaphoreRelease = new Action0() {
public void call() {
if (semaphoreHasBeenReleased.compareAndSet(false, true)) {
executionSemaphore.release();
}
}
};
Action1 markExceptionThrown = new Action1() {
public void call(Throwable t) {
AbstractCommand.this.eventNotifier.markEvent(HystrixEventType.EXCEPTION_THROWN, AbstractCommand.this.commandKey);
}
};
if (executionSemaphore.tryAcquire()) {
try {
this.executionResult = this.executionResult.setInvocationStartTime(System.currentTimeMillis());
return this.executeCommandAndObserve(_cmd).doOnError(markExceptionThrown).doOnTerminate(singleSemaphoreRelease).doOnUnsubscribe(singleSemaphoreRelease);
} catch (RuntimeException var7) {
return Observable.error(var7);
}
} else {
return this.handleSemaphoreRejectionViaFallback();
}
} else {
return this.handleShortCircuitViaFallback();
}
}
allowRequest是判断断路器是否开启关闭状态。如果开启,直接执行fallback降级;如果关闭进行健康检查,并继续执行。
public boolean allowRequest() {
if ((Boolean)this.properties.circuitBreakerForceOpen().get()) {
return false;
} else if ((Boolean)this.properties.circuitBreakerForceClosed().get()) {
this.isOpen();
return true;
} else {
return !this.isOpen() || this.allowSingleTest();
}
}
public boolean allowSingleTest() {
long timeCircuitOpenedOrWasLastTested = this.circuitOpenedOrLastTestedTime.get();
return this.circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + (long)(Integer)this.properties.circuitBreakerSleepWindowInMilliseconds().get() && this.circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis());
}
public boolean isOpen() {
if (this.circuitOpen.get()) {
return true;
} else {
HealthCounts health = this.metrics.getHealthCounts();
if (health.getTotalRequests() < (long)(Integer)this.properties.circuitBreakerRequestVolumeThreshold().get()) {
return false;
} else if (health.getErrorPercentage() < (Integer)this.properties.circuitBreakerErrorThresholdPercentage().get()) {
return false;
} else if (this.circuitOpen.compareAndSet(false, true)) {
this.circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
return true;
} else {
return true;
}
}
}
我们需要关注,allowSingleTest,如果断路器开启了,我们允许一个进行测试,连接成功并且短路开启时间+休眠的时间或者上一次执行测试请求时间已经到了则断路器关闭,不行则打开。
接着尝试获取信号量实例,如果获取不到,则也失败(hystrix的隔离模式有信号量和线程池2种,这里如果没开启信号量模式,这里的TryableSemaphore tryAcquire默认返回的都是true),接着在进入executeCommandAndObserve方法。后续则失败进入fallback处理,或者进行run方法。
fallback处理会取出我们之前已经在配置的类,调用返回。
run方法如果正常处理的话,则会调用SynchronousMethodHandler进行后续处理,与Feign源码一致;
总结一下:Hystrix源码还是很难阅读,但是不影响我们跟踪代码,通过跟踪代码会很清楚的了解到代码运行。尽量debug模式去查看代码。Hystrix暂时到这,后续会补上新的理解。