2014-10-14 7 views
8

Ich verwende Feder-Cloud-Starter (dh .. Spring-Boot mit allen Microservices Funktionen). Wenn ich die Hystrix-Methode in einer Komponente mit dem javanica @HystrixCommand annotiert habe, folge den Anweisungen auf der javanica github-Site (https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica), damit diese Methode async ausgeführt wird, unabhängig davon, ob ich ihre 'Future <>' oder die reaktive Ausführung 'Observable < verwende > ', nichts läuft/führt aus und ich bekomme java.lang.ClassCastException: springbootdemo.EricComponent$1 cannot be cast to springbootdemo.Eric immer wenn ich versuche, das Ergebnis zu ziehen (im Fall von Future <>) oder einen Rückruf (im Falle von Reactive Execution .. und println nicht auslösen, so dass es wirklich nicht ausgeführt wurde).Hystrix Async-Methoden innerhalb von Javanica läuft nicht in Spring-Boot-Java-Anwendung

public class Application { ... 
} 
@RestController 
@RequestMapping(value = "/makebunchofcalls/{num}") 
class EricController { .. 

    @RequestMapping(method={RequestMethod.POST}) 
    ArrayList<Eric> doCalls(@PathVariable Integer num) throws IOException { 
     ArrayList<Eric> ale = new ArrayList<Eric>(num); 
     for (int i =0; i<num; i++) { 
      rx.Observable<Eric> oe = this.ericComponent.doRestTemplateCallAsync(i); 
      oe.subscribe(new Action1<Eric>() { 
       @Override 
       public void call(Eric e) { // AT RUNTIME, ClassCastException 
        ale.add(e); 
       } 
      }); 
     } 

     return ale; 
    } 

@Component 
class EricComponent { ... 

    // async version =========== using reactive execution via rx library from netflix ============== 

    @HystrixCommand(fallbackMethod = "defaultRestTemplateCallAsync", commandKey = "dogeAsync") 
    public rx.Observable<Eric> doRestTemplateCallAsync(int callNum) { 
     return new ObservableResult<Eric>() { 
      @Override 
      public Eric invoke() { // NEVER CALLED 
       try { 
        ResponseEntity<String> result = restTemplate.getForEntity("http://doges/doges/24232/photos", String.class); // actually make a call 
        System.out.println("*************** call successfull: " + new Integer(callNum).toString() + " *************"); 
       } catch (Exception ex) { 
        System.out.println("=============== call " + new Integer(callNum).toString() + " not successfull: " + ex.getMessage() + " ============="); 
       } 
       return new Eric(new Integer(callNum).toString(), "ok"); 
      } 
     }; 
    } 

    public rx.Observable<Eric> defaultRestTemplateCallAsync(int callNum) { 
     return new ObservableResult<Eric>() { 
      @Override 
      public Eric invoke() { 
       System.out.println("!!!!!!!!!!!!! call bombed " + new Integer(callNum).toString() + "!!!!!!!!!!!!!"); 
       return new Eric(new Integer(callNum).toString(), "bomb"); 
      } 
     }; 
    } 
} 

Warum sollte ich einen EricComponent$1 anstelle eines Eric werden immer wieder? BTW, Eric ist nur eine einfache Klasse mit 2 Strings ... es wird weggelassen.

Ich denke, dass ich explizit ausführen muss, aber das spielt auf mich an, weil: 1) es mit Future <> die queue() Methode nicht verfügbar ist, wie die Dokumentation behauptet und 2) mit Observable <> tun es gibt wirklich keinen Weg es auszuführen, den ich bekomme.

Antwort

3

Haben Sie die Annotation @EnableHystrix für Ihre Anwendungsklasse?

Die subscribe-Methode ist asynchron und Sie versuchen, eine Liste in einer synchronen Controller-Methode aufzufüllen, damit dort ein Problem auftreten kann. Können Sie die subscribe zu toBlockingObservable().forEach() ändern und sehen, ob das hilft?

Update # 1 Ich konnte kopieren. Ihre Standardmethode sollte keine Observable<Eric>, nur eine Eric zurückgeben.

public Eric defaultRestTemplateCallAsync(final int callNum) { 
    System.out.println("!!!!!!!!!!!!! call bombed " + new Integer(callNum) + "!!!!!!!!!!!!!"); 
    return new Eric(new Integer(callNum).toString(), "bomb"); 
} 

Update # 2 meinen Code Siehe hier https://github.com/spencergibb/communityanswers/tree/so26372319

Update # 3 Als ich aus dem fallbackMethod Attribut kommentierte es darüber beschwert, dass sie nicht für eine öffentliche Version von EricComponent finden konnten, AOP. Ich machte EricComponentpublic static und es funktionierte. Eine Top-Level-Klasse in einer eigenen Datei würde funktionieren. Mein Code, oben verlinkt, funktioniert (vorausgesetzt, der restTemplate-Aufruf funktioniert) und gibt n OK zurück.

+0

Dank @spencergibb für Ihre Zeit, die Sie dafür ausgegeben haben. Ich hatte @EnableHystrix .. und war in der Lage zu vermeiden, die ClassCastException nach Ihrem Vorschlag zu ersetzen "Observable " zu 'Eric' von der Standardeinstellung. Jemand sollte die Javanica-Dokumentation aktualisieren, um dies zu bestätigen. Wenn ich das aber ausführe, bekomme ich alle "Callbombed" -Drucker. Außerdem wird die 'invoke()' Methode auf dem 'ObservableResult ' immer noch nie ausgeführt. – RubesMN

+0

Nach Ihrem Update # 3, stellt sich heraus, dass die Trennung von EricComponent in seine eigene Datei perfekt funktionierte. Alles läuft jetzt. Darüber hinaus funktioniert auch das Umschalten auf BlockingObservables und Non-Blocking über reguläre Observables und liefert mir das, was ich für mein POC benötige. Nochmals vielen Dank an @spencergibb. – RubesMN