web-dev-qa-db-fra.com

Spring WebFlux (Flux): comment publier dynamiquement

Je suis nouveau dans la programmation réactive et Spring WebFlux. Je souhaite que mon application 1 publie l'événement Server Sent via Flux et mon application 2 l'écoute en continu.

Je souhaite que Flux publie à la demande (par exemple, lorsque quelque chose se produit). Tout l'exemple que j'ai trouvé est d'utiliser Flux.interval pour publier périodiquement un événement, et il ne semble pas possible d'ajouter/modifier le contenu dans Flux une fois qu'il est créé.

Comment puis-je atteindre mon objectif? Ou je me trompe totalement sur le plan conceptuel.

14
John Zhang

Publiez "dynamiquement" à l'aide de FluxProcessor et FluxSink

L'une des techniques pour fournir manuellement des données à Flux consiste à utiliser FluxProcessor#sink méthode comme dans l'exemple suivant

@SpringBootApplication
@RestController
public class DemoApplication {

    final FluxProcessor processor;
    final FluxSink sink;
    final AtomicLong counter;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);

    }

    public DemoApplication() {
        this.processor = DirectProcessor.create().serialize();
        this.sink = processor.sink();
        this.counter = new AtomicLong();
    }

    @GetMapping("/send")
    public void test() {
        sink.next("Hello World #" + counter.getAndIncrement());
    }

    @RequestMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent> sse() {
        return processor.map(e -> ServerSentEvent.builder(e).build());
    }
}

Ici, j'ai créé DirectProcessor afin de prendre en charge plusieurs abonnés, qui écouteront le flux de données. De plus, j'ai fourni FluxProcessor#serialize qui fournit une prise en charge sûre du multiproducteur (invocation à partir de différents threads sans violation des règles de spécification des flux réactifs, en particulier règle 1. ). Enfin, en appelant " http: // localhost: 8080/send " nous verrons le message Hello World #1 (bien sûr, uniquement si vous vous êtes connecté à " http: // localhost: 808 " précédemment)

23
Oleh Dokuka

Juste une autre idée, en utilisant EmitterProcessor comme passerelle vers le flux

    import reactor.core.publisher.EmitterProcessor;
    import reactor.core.publisher.Flux;

    public class MyEmitterProcessor {
        EmitterProcessor<String> emitterProcessor;

        public static void main(String args[]) {

            MyEmitterProcessor myEmitterProcessor = new MyEmitterProcessor();
            final Flux<String> publisher = myEmitterProcessor.getPubisher();
            myEmitterProcessor.onNext("A");
            myEmitterProcessor.onNext("B");
            myEmitterProcessor.onNext("C");
            myEmitterProcessor.complete();

            publisher.subscribe(x -> System.out.println(x));

        }

        public Flux<String> getPublisher() {
            emitterProcessor = EmitterProcessor.create();
            return emitterProcessor.map(x -> "consume: " + x);
        } 

        public  void onNext(String nextString) {
            emitterProcessor.onNext(nextString);
        }

        public  void complete() {
            emitterProcessor.onComplete();
        }
    }

Plus d'informations, voir ici dans la doc Reactor . Le document lui-même recommande que "la plupart du temps, vous devriez éviter d'utiliser un processeur. Ils sont plus difficiles à utiliser correctement et sujets à certains cas de coin. MAIS je ne sais pas quel genre de cas d'angle.

1
CheGola