Could someone help me to understand the difference between:
Mono.defer()
Mono.create()
Mono.just()
How to use it properly?
The Mono. just method is the simplest method for Mono generation. It takes a single value and generates a finite Mono stream from it. A completion event is published after publishing the specified value: Mono.
when you run Mono. just() it creates immediately an Observable(Mono)and reuses it but when you use defer it doesn't create it immediately it creates a new Observable in every subscribe. Your explanation is not totally right. There is nothing such as "create new Observable".
Mono. create(monoSinkConsumer) is the most advanced method that gives you the full control over the emitted values. Instead of the need to return Mono instance from the callback (as in Mono. defer ), you get control over the MonoSink<T> that lets you emit values through MonoSink.
A Flux object represents a reactive sequence of 0.. N items, while a Mono object represents a single-value-or-empty (0..1) result. This distinction carries a bit of semantic information into the type, indicating the rough cardinality of the asynchronous processing.
Mono.just(value)
is the most primitive - once you have a value you can wrap it into a Mono and subscribers down the line will get it.
Mono.defer(monoSupplier)
lets you provide the whole expression that supplies the resulting Mono
instance. The evaluation of this expression is deferred until somebody subscribes. Inside of this expression you can additionally use control structures like Mono.error(throwable)
to signal an error condition (you cannot do this with Mono.just
).
Mono.create(monoSinkConsumer)
is the most advanced method that gives you the full control over the emitted values. Instead of the need to return Mono
instance from the callback (as in Mono.defer
), you get control over the MonoSink<T>
that lets you emit values through MonoSink.success()
, MonoSink.success(value)
, MonoSink.error(throwable)
methods.
Reactor documentation contains a few good examples of possible Mono.create
use cases: link to doc.
The general advice is to use the least powerful abstraction to do the job: Mono.just -> Mono.defer -> Mono.create
.
Although in general I agree with (and praise) @IlyaZinkovich's answer, I would be careful with the advice
The general advice is to use the least powerful abstraction to do the job:
Mono.just
->Mono.defer
->Mono.create
.
In the reactive approach, especially if we are beginners, it's very easy to overlook which the "least powerful abstraction" actually is. I am not saying anything else than @IlyaZinkovich, just depicting one detailed aspect.
Here is one specific use case where the more powerful abstraction Mono.defer()
is preferable over Mono.just()
but which might not be visible at the first glance.
See also:
We use switchIfEmpty()
as a subscription-time branching:
// First ask provider1
provider1.provide1(someData)
// If provider1 did not provide the result, ask the fallback provider provider2
.switchIfEmpty(provider2.provide2(someData))
public Mono<MyResponse> provide2(MyRequest someData) {
// The Mono assembly is needed only in some corner cases
// but in fact it is always happening
return Mono.just(someData)
// expensive data processing which might even fail in the assemble time
.map(...)
.map(...)
...
}
provider2.provide2()
accepts someData
only when provider1.provide1()
does not return any result, and/or the method assembly of the Mono
returned by provider2.provide2()
is expensive and even fails when called on wrong data.
It this case defer()
is preferable, even if it might not be obvious at the first glance:
provider1.provide1(someData)
// ONLY IF provider1 did not provide the result, assemble another Mono with provider2.provide()
.switchIfEmpty(Mono.defer(() -> provider2.provide2(someData)))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With