Пример реального контроллера с Spring 5: Web Reactive

Я хочу участвовать в мире реактивного программирования с помощью Spring. Как я понял, это дает мне выбор между двумя разными парадигмами: основанной на аннотациях (с известными нам @Controller, @RequestMapping) и реактивной (который предназначен для устранения "аннотационного ада").

Моя проблема в непонимании того, как будет выглядеть типичный реактивный контроллер. Есть три концептуальных интерфейса, которые я могу использовать в своем классе контроллера:

HandlerFunction<T> (1) — я определяю метод для каждого конкретного ServerRequest, который возвращает конкретный экземпляр HandlerFunction<T>, затем регистрирую эти методы на маршрутизаторе. Верно?

RouterFunction (2) и FilterFunction (3) — есть ли конкретное место, куда следует поместить все RequestPredicate с соответствующими HandlerFunction? Или я могу сделать это отдельно в каждом контроллере (как я делал с аннотационным подходом)? Если да, то как тогда уведомить глобальный обработчик (маршрутизатор, если есть?), чтобы применить эту часть маршрутизатора с этого контроллера?

Вот как я сейчас вижу «шаблон» реактивного контроллера:

public class Controller {
    // handlers
    private HandlerFunction<ServerResponse> handleA() {
        return request -> ok().body(fromObject("a"));
    }

    // router
    public RouterFunction<?> getRouter() {
        return route(GET("/a"), handleA()).and(
               route(GET("/b"), handleB()));
    }

    // filter
    public RouterFunction<?> getFilter() {
        return route(GET("/c"), handleC()).filter((request, next) -> next.handle(request));
    }
}

И, наконец, как сказать, что это контроллер, не пометив его аннотацией?

Я прочитал справку по Spring и все сообщения, связанные с этой проблемой, в официальном блоге. Образцов много, но все они вырваны из контекста (ИМХО) и я не могу собрать их в полную картину.

Я был бы признателен, если бы вы могли привести реальный пример и передовой опыт организации взаимодействия между этими функциями.


person Andrew Tobilko    schedule 05.01.2017    source источник
comment
Это, вероятно, слишком широко, особенно потому, что, хотя API, вероятно, в основном стабилен, Spring 5 еще даже технически не находится в RC (а Spring Security Reactive все еще находится в основной разработке).   -  person chrylis -cautiouslyoptimistic-    schedule 05.01.2017
comment
Мир реактивного программирования с Spring... дает мне выбор между двумя разными парадигмами: основанной на аннотациях и реактивной Должно быть что-то вроде основанной на аннотациях и функциональной. Оба являются реактивными, только стиль на основе аннотаций имеет классический контроллер.   -  person a better oliver    schedule 05.01.2017
comment
Я думаю, что здесь спрашивают, как организовать код, особенно в случае функциональной модели. Я тоже боролся с этим. В примере кода мы должны объявить все сопоставления запросов (маршруты) в одной длинной цепочке в стиле НЛП. Это вводит связь между маршрутами, которые не нужно упоминать в одном и том же файле класса, и если я попытаюсь создать классы, специфичные для обработчика, их маршруты будут храниться отдельно. Подход, основанный на аннотациях, похоже, может решить эти проблемы, но мне еще предстоит заставить этот метод работать. Даже если это сработало, зачем функциональный подход?   -  person allenru    schedule 13.03.2017


Ответы (2)


Это не пример из реального мира, но пока я рассматриваю какую-то организацию в этом:

https://github.com/LearningByExample/reactive-ms-example

person Juan Medina    schedule 23.04.2017

Что касается меня:

RouterFunction является ближайшим аналогом @Controller (точнее @RequestMapping) с точки зрения новой Весенний подход:

Входящие запросы направляются функциям-обработчикам с RouterFunction (т. е. Function>). Функция маршрутизатора оценивается как функция обработчика, если она соответствует; в противном случае он возвращает пустой результат. RouterFunction имеет ту же цель, что и аннотация @RequestMapping. Тем не менее, есть важное различие: с аннотацией ваш маршрут ограничен тем, что может быть выражено через значения аннотации, и их обработка не является тривиальной для переопределения; с функциями маршрутизатора код обработки находится прямо перед вами: вы можете легко переопределить или заменить его.

Затем вместо Spring Boot SpringApplication.run в основном методе ваш сервер запуска вручную:

// route is your route function
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route); 
HttpServlet servlet = new ServletHttpHandlerAdapter(httpHandler);
Tomcat server = new Tomcat();
Context rootContext = server.addContext("",
System.getProperty("java.io.tmpdir"));
Tomcat.addServlet(rootContext, "servlet", servlet);
rootContext.addServletMapping("/", "servlet");
tomcatServer.start();

Различают как реактивный, так и нереактивный подход. Это проиллюстрировано на Spring github

person Sergii Getman    schedule 02.02.2017
comment
спасибо за ответ, но больше всего меня интересовало как выглядит контроллер и как организовать взаимодействие между такими контроллерами. Ваш фрагмент ярко иллюстрирует беспорядок, который будет, когда мы соберем глобальные/общие вещи (например, RouterFunction становится, если собрать все вещи в одном месте сразу). - person Andrew Tobilko; 03.02.2017
comment
спасибо за ссылку на github, но я действительно не хочу писать всю логику маршрутизации в методе main или в методе с именем вроде configureGlobalRouting где-то. - person Andrew Tobilko; 03.02.2017
comment
@AndrewTobilko, я могу предположить, что новой весной я буду очень похож на структуру ratpack: ratpack.io/manual/current/ - person Sergii Getman; 03.02.2017