我正在尝试了解Spring Boot和Hystrix,并且无法让后备方法工作。我尝试了两种方法@HystrixCommand
和@FeignClient
。我可以获得@HystrixCommand
但不能@FeignClient
。大多数代码都基于我在搜索时看到的示例,所以我认为我非常接近,但必须遗漏一些至关重要的内容。
这是Spring Boot应用程序和REST控制器。我在同一个应用程序中尝试这两种方法。它正在与尤里卡注册。我没有运行hello-world
服务,所以它应该总是后备。
package com.example.goodBye.service;
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
@SpringBootApplication
public class GoodByeServiceApplication {
private final static AtomicInteger counter = new AtomicInteger();
private final static Logger logger = LoggerFactory.getLogger(GoodByeServiceApplication.class);
public static void main(String[] args) {
SpringApplication.run(GoodByeServiceApplication.class, args);
}
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
@RefreshScope
@RestController
class MessageController {
@Autowired
private HelloClient helloClient;
@Autowired
private HelloService helloService;
@Value("${message:Good Bye Default}")
private String message;
@RequestMapping(value = "/message", produces = "application/json")
public Message getMessage(@RequestParam(value = "name", defaultValue = "Anonymous") String name) {
return new Message(counter.incrementAndGet(), String.format("%s from %s", this.message, name));
}
@RequestMapping(value = "/hello", produces = "application/json")
public Message sayHello(@RequestParam(value = "name", defaultValue = "Creepy") String name) {
Message hello = helloService.sayHello(name);
return new Message(counter.incrementAndGet(), String.format("%s/%s from %s", hello.getMessage(), message, name));
}
@RequestMapping(value = "/helloAgain", produces = "application/json")
public Message sayHelloAgain(@RequestParam(value = "name", defaultValue = "Creepy") String name) {
Message hello = helloClient.sayHello(name);
return new Message(counter.incrementAndGet(), String.format("%s/%s from %s", hello.getMessage(), message, name));
}
}
static class Message {
private int count;
private String message;
public Message() {
}
public Message(int count, String message) {
this.count = count;
this.message = message;
}
public int getCount() {
return count;
}
public String getMessage() {
return message;
}
}
}
以下是@HystrixCommand
尝试的尝试。当我在后备方法中设置断点时,我确实在调用堆栈中看到了Hystrix。
@Service
class HelloService {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "rude")
public Message sayHello(String name) {
Message ret = null;
List<ServiceInstance> instances = discoveryClient.getInstances("hello-world");
...
ResponseEntity<Message> resp = restTemplate.getForEntity(uri, Message.class, params);
ret = resp.getBody();
return ret;
}
public Message rude(String name) {
return new Message(counter.incrementAndGet(), String.format("%s was rather rude!", name));
}
}
以下是@FeignClient
无效的豁免。该程序抛出com.netflix.client.ClientException: Load balancer does not have available server for client: hello-world
,调用堆栈不包含任何Hystrix类。
@FeignClient(value = "hello-world", fallback = HelloClientFallback.class)
interface HelloClient {
@RequestMapping(value = "/message", method = RequestMethod.GET)
public Message sayHello(String name);
}
@Component
class HelloClientFallback implements HelloClient {
@Override
public Message sayHello(String name) {
return new Message(counter.incrementAndGet(), String.format("%s is not much better", name));
}
}
我将不胜感激任何帮助。它可能是一些愚蠢的东西,但一直盯着它看,我没有看到它。
谢谢,Wes。
如果有帮助,这是失败的调用堆栈。
com.netflix.client.ClientException: Load balancer does not have available server for client: hello-world
at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:483) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:184) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2]
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.call(LoadBalancerCommand.java:180) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2]
at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber$1.call(OperatorRetryWithPredicate.java:127) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.enqueue(TrampolineScheduler.java:73) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.schedulers.TrampolineScheduler$InnerCurrentThreadScheduler.schedule(TrampolineScheduler.java:52) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:79) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OperatorRetryWithPredicate$SourceSubscriber.onNext(OperatorRetryWithPredicate.java:45) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.util.ScalarSynchronousObservable$WeakSingleProducer.request(ScalarSynchronousObservable.java:276) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Subscriber.setProducer(Subscriber.java:209) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:138) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.util.ScalarSynchronousObservable$JustOnSubscribe.call(ScalarSynchronousObservable.java:129) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) ~[rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Observable.subscribe(Observable.java:10307) ~[rxjava-1.1.10.jar:1.1.10]
at rx.Observable.subscribe(Observable.java:10274) ~[rxjava-1.1.10.jar:1.1.10]
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:445) ~[rxjava-1.1.10.jar:1.1.10]
at rx.observables.BlockingObservable.single(BlockingObservable.java:342) ~[rxjava-1.1.10.jar:1.1.10]
at com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:117) ~[ribbon-loadbalancer-2.2.2.jar:2.2.2]
at org.springframework.cloud.netflix.feign.ribbon.LoadBalancerFeignClient.execute(LoadBalancerFeignClient.java:63) ~[spring-cloud-netflix-core-1.3.0.RC1.jar:1.3.0.RC1]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:97) ~[feign-core-9.4.0.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) ~[feign-core-9.4.0.jar:na]
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-9.4.0.jar:na]
at com.example.goodBye.service.$Proxy108.sayHello(Unknown Source) ~[na:na]
at com.example.goodBye.service.GoodByeServiceApplication$MessageController.sayHelloAgain(GoodByeServiceApplication.java:79) ~[main/:na]
这是成功的调用堆栈,但由于Hystrix在不同的线程中运行,因此无法显示任何有用的内容。
java.lang.IllegalStateException: Call stack of successful fallback
at com.example.goodBye.service.GoodByeServiceApplication$HelloService.rude(GoodByeServiceApplication.java:147) ~[main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_45]
at com.netflix.hystrix.contrib.javanica.command.MethodExecutionAction.execute(MethodExecutionAction.java:116) [hystrix-javanica-1.5.10.jar:1.5.10]
at com.netflix.hystrix.contrib.javanica.command.MethodExecutionAction.executeWithArgs(MethodExecutionAction.java:93) [hystrix-javanica-1.5.10.jar:1.5.10]
at com.netflix.hystrix.contrib.javanica.command.GenericCommand$2.execute(GenericCommand.java:76) [hystrix-javanica-1.5.10.jar:1.5.10]
at com.netflix.hystrix.contrib.javanica.command.AbstractHystrixCommand.process(AbstractHystrixCommand.java:145) [hystrix-javanica-1.5.10.jar:1.5.10]
at com.netflix.hystrix.contrib.javanica.command.GenericCommand.getFallback(GenericCommand.java:71) [hystrix-javanica-1.5.10.jar:1.5.10]
at com.netflix.hystrix.HystrixCommand$3.call(HystrixCommand.java:322) [hystrix-core-1.5.10.jar:1.5.10]
at com.netflix.hystrix.HystrixCommand$3.call(HystrixCommand.java:318) [hystrix-core-1.5.10.jar:1.5.10]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:46) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) [rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OperatorOnErrorResumeNextViaFunction$4.onError(OperatorOnErrorResumeNextViaFunction.java:142) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87) [rxjava-1.1.10.jar:1.1.10]
at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$3.onError(AbstractCommand.java:1194) [hystrix-core-1.5.10.jar:1.5.10]
at rx.internal.operators.OperatorSubscribeOn$1$1.onError(OperatorSubscribeOn.java:59) [rxjava-1.1.10.jar:1.1.10]
at rx.observers.Subscribers$5.onError(Subscribers.java:230) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach$DoOnEachSubscriber.onError(OnSubscribeDoOnEach.java:87) [rxjava-1.1.10.jar:1.1.10]
at rx.observers.Subscribers$5.onError(Subscribers.java:230) [rxjava-1.1.10.jar:1.1.10]
at com.netflix.hystrix.AbstractCommand$DeprecatedOnRunHookApplication$1.onError(AbstractCommand.java:1431) [hystrix-core-1.5.10.jar:1.5.10]
at com.netflix.hystrix.AbstractCommand$ExecutionHookApplication$1.onError(AbstractCommand.java:1362) [hystrix-core-1.5.10.jar:1.5.10]
at rx.observers.Subscribers$5.onError(Subscribers.java:230) [rxjava-1.1.10.jar:1.1.10]
at rx.observers.Subscribers$5.onError(Subscribers.java:230) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:44) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeThrow.call(OnSubscribeThrow.java:28) [rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:51) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDefer.call(OnSubscribeDefer.java:35) [rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:41) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeDoOnEach.call(OnSubscribeDoOnEach.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30) [rxjava-1.1.10.jar:1.1.10]
at rx.Observable.unsafeSubscribe(Observable.java:10211) [rxjava-1.1.10.jar:1.1.10]
at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94) [rxjava-1.1.10.jar:1.1.10]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:56) [hystrix-core-1.5.10.jar:1.5.10]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction$1.call(HystrixContexSchedulerAction.java:47) [hystrix-core-1.5.10.jar:1.5.10]
at com.netflix.hystrix.strategy.concurrency.HystrixContexSchedulerAction.call(HystrixContexSchedulerAction.java:69) [hystrix-core-1.5.10.jar:1.5.10]
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55) [rxjava-1.1.10.jar:1.1.10]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_45]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_45]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_45]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_45]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]
答案 0 :(得分:9)
您的日志显示您正在使用spring cloud netflix 1.3.0RC1。从这个版本开始,FeignClient不会使用HystrixCommand包装方法。如果不存在则需要在类路径上添加hystrix并设置选项feign.hystrix.enabled=true
。
默认情况下,Feign客户端不再在Hystrix命令中包装方法(#1277)。您必须在类路径上使用Hystrix,并设置feign.hystrix.enabled = true以使Feign在Hystrix命令中自动换行方法。
请参阅发行说明。 https://github.com/spring-projects/spring-cloud/wiki/Spring-Cloud-Dalston-Release-Notes