3

i have a RESTful api application build on spring mvc.

recently i was doing something integration between spring mvc and reactive stream (like rxjava and project-reactor) and try to make the application more reactive.

i have just build some demo like this below:

1.for rxjava,i use PublishSubject

private SerializedSubject<StreamResult, StreamResult> subject = PublishSubject.<StreamResult>create().toSerialized();

public ReactiveStreamController() {
    this.subject.subscribe(streamResult -> {
        String id = streamResult.getRequest().getParameter("id");
        System.out.println("[" + Thread.currentThread().getName() + "] request received. id = " + id);
        String random = StringUtils.isBlank(id) ? StringUtils.EMPTY : id;
        ResponseVO vo = new ResponseVO(200, "success = " + random);
        streamResult.getFuture().complete(vo);
    }, Throwable::printStackTrace);
}

@ResponseBody
@RequestMapping(value = "/rxJava", method = RequestMethod.GET)
public CompletableFuture<ResponseVO> rxJavaController(HttpServletRequest httpServletRequest) {
    StreamResult sr = new StreamResult();
    sr.setRequest(httpServletRequest);
    subject.onNext(sr);
    return sr.getFuture();
}

2.for project reactor

@ResponseBody
@RequestMapping(value = "/reactorCodeNew", method = RequestMethod.GET)
public CompletableFuture<ResponseVO> reactorCoreNewParadigm(HttpServletRequest servletRequest) {
    Mono<ResponseVO> mono = Mono.just(servletRequest)
            .subscribeOn(executorService)
            .map(request -> {
                String id = request.getParameter("id");
                System.out.println("[" + Thread.currentThread().getName() + "] request received. id = " + id);
                String random = StringUtils.isBlank(id) ? StringUtils.EMPTY : id;
                ResponseVO vo = new ResponseVO(200, "success = " + random);
                return vo;
            })
            .timeout(Duration.ofSeconds(2), Mono.just(new ResponseVO(500, "error")));
    return mono.toCompletableFuture();
}

while running both the demos, i don't quite see too many difference between just using a java's CompletableFuture to supply among the controller method.

what i understand reactive stream and what i want is treating the servlet request as a stream and cosume it with some feature like backpressure.

i wanna know: 1. is there a better way to make the application more reactive? 2. is it correct or compatible to integrate spring mvc with reactive streams? if yes, how can i performce feature like backpressure?

i realize maybe i forgot to declare why/how i return a completablefuture in the controller, actually i inject a customized MethodReturnValueHandler to transform the CompletableFuture to DefferdResult.

public class CompletableFutureMethodReturnValueHandler extends DeferredResultMethodReturnValueHandler {

@Override
public boolean supportsReturnType(MethodParameter returnType) {
    return CompletableFuture.class.isAssignableFrom(returnType.getParameterType());
}

@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

    CompletableFuture<?> completableFuture = (CompletableFuture<?>) returnValue;

    super.handleReturnValue(CompletableDeferredResult.newInstance(completableFuture), returnType, mavContainer, webRequest);
}
}
  • Recently posted Spring blog on exactly this: https://spring.io/blog/2016/07/20/notes-on-reactive-programming-part-iii-a-simple-http-server-application – Will Jul 25 '16 at 09:20

1 Answers1

3

Spring MVC is based on the Servlet API and is mostly blocking internally, so it cannot leverage reactive streams behavior. Writing adapters for the Controller layer won't be enough.

The Spring team is working on a separate initiative for this purpose. Follow SPR-14161 and the Spring blog (including this and this) to know more about reactive Spring.

Brian Clozel
  • 56,583
  • 15
  • 167
  • 176