As the book continues, we learn about the dependency injection features of Quarkus. This time, let’s look at the concept of subscriptions.

Subscribe

Subscriptions are a concept you see a lot in Reactive programming.

Let’s start with a piece of code. Below, is a query interface that retrieves all brand information and returns it.

    @Inject
    BrandInfoRepository brandInfoRepository;

    @Route(path = "/brandInfos", methods = HttpMethod.GET)
    void brandInofs2(RoutingContext rc) {
        brandInfoRepository.findAll()
            .list()
            .subscribe()
            .with(brandInfos -> {
                    LOGGER.info("size:{}", brandInfos.size());
                    handleJson(rc, brandInfos);
                },
                t -> handleFail(rc, t));
    }
Copy the code

And the subscribe() method is to subscribe. Let’s spread out the chain notation above.

    @Inject
    BrandInfoRepository brandInfoRepository;

    @Route(path = "/brandInfos", methods = HttpMethod.GET)
    void brandInfos(RoutingContext rc) {
        PanacheQuery<BrandInfo> query = brandInfoRepository.findAll();
        Uni<List<BrandInfo>> listUni = query.list();
        UniSubscribe<List<BrandInfo>> uniSubscribe = listUni.subscribe();
        Consumer<List<BrandInfo>> listConsumer = brandInfos -> {
            LOGGER.info("btandInfos size: {}", brandInfos.size());
            handleJson(rc, brandInfos);
        };
        Consumer<Throwable> throwableConsumer = t -> handleFail(rc, t);
        uniSubscribe.with(listConsumer, throwableConsumer);
    }
Copy the code
  1. Line 1 returns PanacheQuery, which is simply building a valid query condition, not initiating the query.
  2. Line 2 returns Uni for asynchronous operations that accept 0 or 1 result.
  3. Line 3 returns UniSubscribe, which is a subscription. (We subscribe to Uni to trigger computation)
  4. Lines 4-7 return to Consumer, the handler if it succeeds.
  5. Line 8 returns Consumer, what to do if it fails.
  6. Line 9.withMethod that tells you what to do in case of success and failure.

Uni

Uni allows you to accept 0 or 1 asynchronous results.


/**
 * A {@link Uni} represents a lazy asynchronous action. It follows the subscription pattern, meaning that the action
 * is only triggered once a {@link UniSubscriber} subscribes to the {@link Uni}.
 * <p>
 * A {@link Uni} can have two outcomes:
 * <ol>
 * <li>An {@code item} event, forwarding the completion of the action (potentially {@code null} if the item
 * does not represent a value, but the action was completed successfully)</li>
 * <li>A {@code failure} event, forwarding an exception</li>
 * </ol>
 * <p>
 * To trigger the computation, a {@link UniSubscriber} must subscribe to the Uni. It will be notified of the outcome
 * once there is an {@code item} or {@code failure} event fired by the observed Uni. A subscriber receives
 * (asynchronously) a {@link UniSubscription} and can cancel the demand at any time. Note that cancelling after
 * having received the outcome is a no-op.
 * <p>
 *
 * @param <T> the type of item produced by the {@link Uni}
 */
public interface Uni<T> {}
Copy the code

We don’t know if Uni returns 0 or 1. Uni is also Quarkus’ most common asynchronous return result.

  1. Uni is a lazy asynchronous operation that follows a subscription model.
  2. Only one subscription can be triggered.
  3. There are only two results. One is that an item is returned indicating that the operation is complete. The other is that an exception is returned.
  4. To trigger calculations, you must subscribe to Uni.

Return an element

Uni<BrandInfo> findOne(String id);
Copy the code

Return a collection

Uni<List<BrandInfo>> findAll();
Copy the code

The subsequent operation

Quarkus provides a wealth of methods for Uni’s subsequent processing, including apis that can be divided into data creation, event methods, and transformation methods.

There are two common subsequent operations: item and subscribe

Item

    @Route(path = "/brandInfos3", methods = HttpMethod.GET)
    Uni<List<BrandInfo>> brandInfos3(RoutingContext rc) {
        return brandInfoRepository.findAll().list()
            // Successfully get a non-empty Item
            .onItem().ifNotNull().transformToUni(entity -> {
                return Uni.createFrom().item(entity);
            })
            // If Item is empty, fail
            .onItem().ifNull().fail();
    }
Copy the code

If you can get the Item, you can proceed directly.

subscribe

    @Route(path = "/brandInfos2", methods = HttpMethod.GET)
    void brandInofs2(RoutingContext rc) {
        brandInfoRepository.findAll()
            .list()
            .subscribe()
            .with(brandInfos -> {
                    LOGGER.info("size:{}", brandInfos.size());
                    handleJson(rc, brandInfos);
                },
                t -> handleFail(rc, t));
    }
Copy the code

Convert to UniSubscribe and work with the subscribed mode.

UniSubscribe

The purpose of UniSubscribe is to subscribe to the results returned asynchronously. It is often possible to convert Uni to a subscription approach to our business code.


/**
 * Allow subscribing to a {@link Uni} to be notified of the different events coming from {@code upstream}.
 * Two kind of events can be received:
 * <ul>
 * <li>{@code item} - the item of the {@link Uni}, can be {@code null}</li>
 * <li>{@code failure} - the failure propagated by the {@link Uni}</li>
 * </ul>
 *
 * @param <T> the type of item
 */
public class UniSubscribe<T> {}Copy the code

Uni is allowed to subscribe to upstream and we can take different events for processing.

When the asynchronous result is returned, UniSubscribe accepts two kinds of events (or consumers, if you like) :

  1. The result that you get back, that isUniIn theItem, this value can benull.
  2. Exception returned, failed, not to mention.

gossip

From the perspective of coding experience, it is still recommended to use the subscription model for data operation, after all, the concept of subscription and consumer are familiar. We dictated the Quarkus asynchronous operation process: after we got a Uni, we subscribed to Uni, which triggered the calculation of item acquisition in Uni, and declared the processing method of success or failure in with.

The main business code is reflected in the process of consumer processing, the overall design is more elegant.