异常:
│ com.netflix.hystrix.exception.HystrixRuntimeException: XxxClient#getXxx() failed and fallback failed. │ at com.netflix.hystrix.AbstractCommand$22.call(AbstractCommand.java:832) │ at com.netflix.hystrix.AbstractCommand$22.call(AbstractCommand.java:807) │ at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onError(OperatorOnErrorResumeNextViaFunction.java:140) │ at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87) │ at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87) │ at com.netflix.hystrix.AbstractCommand$DeprecatedOnFallbackHookApplication$1.onError(AbstractCommand.java:1472) │ at com.netflix.hystrix.AbstractCommand$FallbackHookApplication$1.onError(AbstractCommand.java:1397) │ at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87) │ at rx.observers.Subscribers$5.onError(Subscribers.java:230) │ at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:44) │ at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:28) │ at rx.Observable.unsafeSubscribe(Observable.java:10327) │ at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51) │ at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) │ at rx.Observable.unsafeSubscribe(Observable.java:10327) │ at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) │ at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) │ at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) │ at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) │ at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) │ at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) │ at rx.Observable.unsafeSubscribe(Observable.java:10327) │ at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) │ at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) │ at rx.Observable.unsafeSubscribe(Observable.java:10327) │ at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) │ at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) │ at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) │ at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) │ at rx.Observable.unsafeSubscribe(Observable.java:10327) │ at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) │ at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) │ at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) │ at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) │ at rx.Observable.unsafeSubscribe(Observable.java:10327) │ at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onError(OperatorOnErrorResumeNextViaFunction.java:142) │ at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87) │ at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87) │ at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$3.onError(AbstractCommand.java:1194) │ at rx.internal.operators.OperatorSubscribeOn$SubscribeOnSubscriber.onError(OperatorSubscribeOn.java:80) │ at rx.observers.Subscribers$5.onError(Subscribers.java:230) │ at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87) │ at rx.observers.Subscribers$5.onError(Subscribers.java:230) │ at com.netflix.hystrix.AbstractCommand$DeprecatedOnRunHookApplication$1.onError(AbstractCommand.java:1431) │ at com.netflix.hystrix.AbstractCommand$ExecutionHookApplication$1.onError(AbstractCommand.java:1362)
问题产生:
通过spring openfeign的FallbackFactory对feign接口进行降级熔断操作;具体问题产生原因是FallbackFactory#create创建的对象,通过反射调用相关方法时,方法内部抛出了 Runtime Exception,也就是说并非降级操作不起作用,而是写的降级方法本身存在问题!比如 方法內抛出了异常、属性注入失败等等
OpenFeign提供的两种降级操作:1、fallback
@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
protected interface TestClient {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
Hello getHello();
@RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
String getException();
}
@Component
static class Fallback implements TestClient {
@Override
public Hello getHello() {
throw new NoFallbackAvailableException("Boom!", new RuntimeException());
}
@Override
public String getException() {
return "Fixed response";
}
}
这种方式最简单,当feign接口调用失败时直接走fallback方法,不足之处在于拿不到具体feign调用失败的err信息
2、fallbackFactory
@FeignClient(name = "testClientWithFactory", url = "http://localhost:${server.port}/",
fallbackFactory = TestFallbackFactory.class)
protected interface TestClientWithFactory {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
Hello getHello();
@RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
String getException();
}
@Component
static class TestFallbackFactory implements FallbackFactory {
@Override
public FallbackWithFactory create(Throwable cause) {
return new FallbackWithFactory();
}
}
static class FallbackWithFactory implements TestClientWithFactory {
@Override
public Hello getHello() {
throw new NoFallbackAvailableException("Boom!", new RuntimeException());
}
@Override
public String getException() {
return "Fixed response";
}
}
通过这种方式就可以在创建fallback实体对象的时候把throwable错误信息传回来
3、fallback与fallbackFactory的差别:
两者最终的处理方式都是一致的,fallbackFactory在真正使用的时候才创建需要的fallback对象,这个时候就很方便的将throwable信息传回;fallback最终也会使用默认的工厂方法:
final class Defaultimplements FallbackFactory { // jul to not add a dependency final Logger logger; final T constant; public Default(T constant) { this(constant, Logger.getLogger(Default.class.getName())); } Default(T constant, Logger logger) { this.constant = checkNotNull(constant, "fallback"); this.logger = checkNotNull(logger, "logger"); } @Override public T create(Throwable cause) { if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "fallback due to: " + cause.getMessage(), cause); } return constant; } @Override public String toString() { return constant.toString(); } }
当然这个默认的工厂方法创建的fallback对象是没有携带throwable信息的
来看看两者最终都会调用fallback的方法:
feign.hystrix.HystrixInvocationHandler#invoke
public Object invoke(final Object proxy, final Method method, final Object[] args)
throws Throwable {
.......
HystrixCommand
简单来说: 两种降级操作 fallback 和 fallbackFactory的处理方式是一致的,如果想要拿到具体的异常信息就使用 fallbackFactory
调试版本: org.springframework.cloud:spring-cloud-openfeign:2.2.5.RELEASE 以及其依赖的io.github.openfeign:feign-hystrix:10.10.1
以上是个人理解,如有问题请指出!
参考 spring-cloud-openfeign



