От новичка до гуру: Курсы программирования на CyberDuff

Spring MVC + DeferredResult добавляет материал Hateoas

Для остального интерфейса используется Spring MVC + RxJava + DeferredResult, возвращаемый из контроллеров.

Я думаю о добавлении поддержки Hateoas в конечные точки. Естественным выбором будет Spring Hateoas. Проблема в том, что Spring Hateoas не будет работать в асинхронной/многопоточной среде, так как он использует ThreadLocal.

Есть ли способ обойти это ограничение? Я так не думаю, но, может быть, у кого-то есть какие-либо предложения.

Кто-нибудь использовал другие API для добавления поддержки Hateoas на остальные конечные точки?

Спасибо.


  • Не могли бы вы указать вашу проблему? поскольку он использует ThreadLocal, сам по себе не является проблемой. 17.02.2015
  • На самом деле проблема в том, что используется ThreadLocal. Запрос обрабатывается в разных потоках. Я имею в виду, что бизнес-логика контроллера выполняется в реактивной среде (RxJava). Когда он возвращается асинхронно, это другой поток, отличный от исходного. Когда Spring Hateoas пытается получить атрибуты запроса, которые хранятся в ThreadLocal, он получает значение null. 18.02.2015
  • Тогда проблема будет заключаться в том, как его использовать. Я не знаю, какая часть Spring HATEOAS обращается к атрибутам запроса. В этом не было бы особого смысла, но я рад оказаться неправым. Сам Spring MVC поддерживает асинхронную обработку. Конкретный пример определенно поможет найти проблему. 18.02.2015

Ответы:


1

Таким образом, решение, которое я использовал, состоит в том, чтобы закрыть атрибуты запроса, а затем применить их как часть оператора лифта.

public class RequestContextStashOperator<T> implements Observable.Operator<T, T> {

    private final RequestAttributes attributes;

    /**
     * Spring hateoas requires the request context to be set but observables may happen on other threads
     * This operator will reapply the context of the constructing thread on the execution thread of the subscriber
     */
    public RequestContextStashOperator() {
        attributes = RequestContextHolder.currentRequestAttributes();
    }
    @Override
    public Subscriber<? super T> call(Subscriber<? super T> subscriber) {
        return new Subscriber<T>() {
            @Override
            public void onCompleted() {
                subscriber.onCompleted();
            }

            @Override
            public void onError(Throwable e) {
                subscriber.onError(e);
            }

            @Override
            public void onNext(T t) {
                RequestContextHolder.setRequestAttributes(attributes);
                subscriber.onNext(t);
            }
        };
    }
}

который вы можете затем использовать на наблюдаемом, например

lift(new RequestContextStashOperator<>())

пока объект создается в том же потоке, что и запрос. Затем вы можете использовать карту после в наблюдаемой цепочке, чтобы сопоставить ваш объект с ресурсом и добавить ссылки ненависти.

09.11.2015
  • Отличное решение! Спасибо за помощь. 05.07.2016
  • Это было очень полезно. Прямо сейчас я хотел бы щелкнуть голосование раз 10, чтобы отпраздновать это. Спасибо. 11.03.2017

  • 2

    Так что ответ немного запоздал, но, возможно, кому-то он будет полезен. Вы правы насчет ThreadLocal - если вы создаете ссылки ненависти в другом потоке, то это происходит с исключением. Я нашел какое-то обходное решение для этого:

    @RequestMapping(path = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    DeferredResult<ResponseEntity<ProductResource>> example(@PathVariable("id") final String productId, final HttpServletRequest request) {
    
        final DeferredResult<ResponseEntity<ProductResource>> deferredResult = new DeferredResult<>();
    
        request.setAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE, request.getContextPath());
        final RequestAttributes requestAttributes = new ServletRequestAttributes(request);
    
        productByIdQuery.byId(UUID.fromString(productId)).subscribe(productEntity -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
                deferredResult.setResult(result, HttpStatus.OK))
        }, deferredResult::setErrorResult);
    
        return deferredResult;
    }
    

    Итак, как видите, я сохраняю RequestAttributes, чтобы позже установить их в обратном вызове. Это решает только часть проблемы — вы получите еще одно исключение, потому что потеряете атрибут contextPath. Чтобы избежать этого, сохраните его явно:

    request.setAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE, request.getContextPath());
    

    После этих изменений вроде бы все работает, но, конечно, выглядит грязно. Я надеюсь, что кто-то может предоставить более элегантное решение.

    28.10.2015
    Новые материалы

    Основы Spring: Bean-компоненты, контейнер и внедрение зависимостей
    Как лего может помочь нашему пониманию Когда мы начинаем использовать Spring, нам бросают много терминов, и может быть трудно понять, что они все означают. Итак, мы разберем основы и будем..

    Отслеживание состояния с течением времени с дифференцированием снимков
    Время от времени что-то происходит и революционизирует часть моего рабочего процесса разработки. Что-то более забавное вместо типичного утомительного и утомительного процесса разработки. В..

    Я предполагаю, что вы имеете в виду методы обработки категориальных данных.
    Я предполагаю, что вы имеете в виду методы обработки категориальных данных. Пожалуйста, проверьте мой пост Инструментарий специалиста по данным для кодирования категориальных переменных в..

    Игра в прятки с данными
    Игра в прятки с данными Я хотел бы, чтобы вы сделали мне одолжение и ответили на следующие вопросы. Гуглить можно в любое время, здесь никто не забивается. Сколько регионов в Гане? А как..

    «Раскрытие математических рассуждений с помощью Microsoft MathPrompter и моделей больших языков»
    TL;DR: MathPrompter от Microsoft показывает, как использовать математические рассуждения с большими языковыми моделями; 4-этапный процесс для улучшения доверия и рассуждений в математических..

    Раскройте свой потенциал в области разработки мобильных приложений: Абсолютная бесплатная серия
    Глава 6: Работа в сети и выборка данных Глава 1: Введение в React Native Глава 2: Основы React Native Глава 3: Создание пользовательского интерфейса с помощью React Native Глава 4:..

    Все о кейсах: Camel, Snake, Kebab & Pascal
    В программировании вы сталкивались с ними при именовании переменной, класса или функции. Поддержание согласованности типов и стилей случаев делает ваш код более читабельным и облегчает совместную..