From 6317569b1c6b90f51ff5cd69fb7c49826152e3f0 Mon Sep 17 00:00:00 2001 From: James Yuzawa Date: Wed, 15 Mar 2023 09:44:22 -0400 Subject: [PATCH 1/2] Use iterators in BodyExtractor and BodyInserter they use less memory and cpu --- .../reactive/AbstractClientHttpRequest.java | 6 ++-- .../web/reactive/function/BodyExtractors.java | 35 +++++++++---------- .../web/reactive/function/BodyInserters.java | 25 ++++++------- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/client/reactive/AbstractClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/reactive/AbstractClientHttpRequest.java index 14346902f2b8..144e0d058da3 100644 --- a/spring-web/src/main/java/org/springframework/http/client/reactive/AbstractClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/reactive/AbstractClientHttpRequest.java @@ -147,8 +147,10 @@ protected Mono doCommit(@Nullable Supplier> writ this.commitActions.add(writeAction); } - List> actions = this.commitActions.stream() - .map(Supplier::get).toList(); + List> actions = new ArrayList<>(this.commitActions.size()); + for (Supplier> commitAction : this.commitActions) { + actions.add(commitAction.get()); + } return Flux.concat(actions).then(); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java index 4baa24b4f14c..0b4d41675586 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java @@ -194,18 +194,16 @@ private static > S readWithMessageReaders( MediaType contentType = Optional.ofNullable(message.getHeaders().getContentType()) .orElse(MediaType.APPLICATION_OCTET_STREAM); - return context.messageReaders().stream() - .filter(reader -> reader.canRead(elementType, contentType)) - .findFirst() - .map(BodyExtractors::cast) - .map(readerFunction) - .orElseGet(() -> { - List mediaTypes = context.messageReaders().stream() - .flatMap(reader -> reader.getReadableMediaTypes(elementType).stream()) - .toList(); - return errorFunction.apply( - new UnsupportedMediaTypeException(contentType, mediaTypes, elementType)); - }); + for (HttpMessageReader messageReader : context.messageReaders()) { + if (messageReader.canRead(elementType, contentType)) { + return readerFunction.apply(cast(messageReader)); + } + } + List mediaTypes = context.messageReaders().stream() + .flatMap(reader -> reader.getReadableMediaTypes(elementType).stream()) + .toList(); + return errorFunction.apply( + new UnsupportedMediaTypeException(contentType, mediaTypes, elementType)); } private static Mono readToMono(ReactiveHttpInputMessage message, BodyExtractor.Context context, @@ -245,12 +243,13 @@ private static Flux unsupportedErrorHandler( private static HttpMessageReader findReader( ResolvableType elementType, MediaType mediaType, BodyExtractor.Context context) { - return context.messageReaders().stream() - .filter(messageReader -> messageReader.canRead(elementType, mediaType)) - .findFirst() - .map(BodyExtractors::cast) - .orElseThrow(() -> new IllegalStateException( - "No HttpMessageReader for \"" + mediaType + "\" and \"" + elementType + "\"")); + for (HttpMessageReader messageReader : context.messageReaders()) { + if (messageReader.canRead(elementType, mediaType)) { + return cast(messageReader); + } + } + throw new IllegalStateException( + "No HttpMessageReader for \"" + mediaType + "\" and \"" + elementType + "\""); } @SuppressWarnings("unchecked") diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java index 7822ff79ebed..0504ddfc167d 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java @@ -373,12 +373,12 @@ else if (adapter != null) { publisher = Mono.just(body); } MediaType mediaType = outputMessage.getHeaders().getContentType(); - return context.messageWriters().stream() - .filter(messageWriter -> messageWriter.canWrite(bodyType, mediaType)) - .findFirst() - .map(BodyInserters::cast) - .map(writer -> write(publisher, bodyType, mediaType, outputMessage, context, writer)) - .orElseGet(() -> Mono.error(unsupportedError(bodyType, context, mediaType))); + for (HttpMessageWriter messageWriter : context.messageWriters()) { + if (messageWriter.canWrite(bodyType, mediaType)) { + return write(publisher, bodyType, mediaType, outputMessage, context, cast(messageWriter)); + } + } + return Mono.error(unsupportedError(bodyType, context, mediaType)); } private static UnsupportedMediaTypeException unsupportedError(ResolvableType bodyType, @@ -406,12 +406,13 @@ private static Mono write(Publisher input, ResolvableType private static HttpMessageWriter findWriter( BodyInserter.Context context, ResolvableType elementType, @Nullable MediaType mediaType) { - return context.messageWriters().stream() - .filter(messageWriter -> messageWriter.canWrite(elementType, mediaType)) - .findFirst() - .map(BodyInserters::cast) - .orElseThrow(() -> new IllegalStateException( - "No HttpMessageWriter for \"" + mediaType + "\" and \"" + elementType + "\"")); + for (HttpMessageWriter messageWriter : context.messageWriters()) { + if (messageWriter.canWrite(elementType, mediaType)) { + return cast(messageWriter); + } + } + throw new IllegalStateException( + "No HttpMessageWriter for \"" + mediaType + "\" and \"" + elementType + "\""); } @SuppressWarnings("unchecked") From 028df53017a63b06ba5146c61050d120c512a6c9 Mon Sep 17 00:00:00 2001 From: James Yuzawa Date: Tue, 21 Mar 2023 21:16:53 -0400 Subject: [PATCH 2/2] Use iterators in BodyExtractor and BodyInserter use an intermediate variable for readability --- .../springframework/web/reactive/function/BodyInserters.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java index 0504ddfc167d..06935a32897e 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/BodyInserters.java @@ -375,7 +375,8 @@ else if (adapter != null) { MediaType mediaType = outputMessage.getHeaders().getContentType(); for (HttpMessageWriter messageWriter : context.messageWriters()) { if (messageWriter.canWrite(bodyType, mediaType)) { - return write(publisher, bodyType, mediaType, outputMessage, context, cast(messageWriter)); + HttpMessageWriter typedMessageWriter = cast(messageWriter); + return write(publisher, bodyType, mediaType, outputMessage, context, typedMessageWriter); } } return Mono.error(unsupportedError(bodyType, context, mediaType));