Можно ли выполнять код без побочных эффектов во время сборки? - PullRequest
0 голосов
/ 14 июля 2020

Я становлюсь немного параноиком, когда вижу такие функции

@Override
    public Mono<List<UserbaseEntityResponse.GroupPrincipal>> merge(UserbaseValidatorResult userbaseValidatorResult,
                                                                   UserbaseEntityResponse userbaseEntityResponse1,
                                                                   UserbaseEntityResponse userbaseEntityResponse2) {
        List<UserbaseEntityResponse.GroupPrincipal> conflictGroupPrincipal = new ArrayList<>();
        userbaseValidatorResult.getResult().getConflicts().forEach(conflicts -> conflicts.forEach(conflict -> {
            UserbaseEntityResponse.GroupPrincipal gp1 = findGroupPrincipalFromGroupName(userbaseEntityResponse1, conflict.getGroupName());
            UserbaseEntityResponse.GroupPrincipal gp2 = findGroupPrincipalFromGroupName(userbaseEntityResponse2, conflict.getGroupName());

            if (userbaseEntityResponse1.getUserbaseId().equals(conflict.getUserbaseId())) {
                conflictGroupPrincipal.add(ImmutableGroupPrincipal.copyOf(gp1)
                        .withName(conflict.getGroupId() + "-" + conflict.getUserbaseId()));
            } else if (userbaseEntityResponse2.getUserbaseId().equals(conflict.getUserbaseId())) {
                conflictGroupPrincipal.add(ImmutableGroupPrincipal.copyOf(gp2)
                        .withName(conflict.getGroupId() + "-" + conflict.getUserbaseId()));
            }

        }));

        return Mono.just(conflictGroupPrincipal);
    }

Весь приведенный выше код return не заключен в Mono, и я думаю, что все операторы выполняются во время сборки. Поскольку в любой из этих операций нет побочных эффектов, все в порядке?

Более важный вопрос заключается в том, когда мы должны оборачивать методы внутри defer, как показано ниже.

public Mono<List<>> merge(args...) {
  return Mono.defer(() -> doMerge(args...));
}

public List<> doMerge(args...) {
  // business logic
}
* 1008 выполнить n / w операций, мы должны отложить выполнение. Я правильно понимаю?

1 Ответ

4 голосов
/ 14 июля 2020

Приведенный вами пример я называю «реактивным методом самозванца». На самом деле это просто синхронный метод, который возвращает реактивного издателя.

Реактивные методы самозванца имеют несколько недостатков:

  1. «Работа» выполняется во время сборки, что нарушает « ничего не произойдет, пока вы не подпишетесь на » дизайн реактивных потоков
  2. «Работа» не может быть перенесена на другой поток через .subscribeOn на возвращенном Mono. Таким образом, если какая-либо из функций, выполняемых в рамках метода, является блокирующей, она может заблокировать событие l oop.
  3. Операторы «устойчивости», такие как .timeout, .repeat и .retry, не будут работать с возвращенным Mono.

Как минимум, вы можете использовать Mono.fromCallable вот так:

return Mono.fromCallable(() -> {

    // ... snip ... construct conflictGroupPrincipal...

    return conflictGroupPrincipal;
});

Вы также можете использовать Mono.defer, как вы упомянули , но в данном случае это излишний, поскольку реализация синхронна. *

...