From 862fa557bde6698252c3fbb6f295dbf12461a630 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Tue, 5 Feb 2019 12:14:51 +0100 Subject: [PATCH] Avoid java.util.stream.Stream usage in hot paths Prior to this commit, profiling sessions would show that using `java.util.stream.Stream` in some hot code paths creates significant garbage. Where streams aren't really required, this commit turns those snippets into imperative logic because those are likely to be called once or multiple times per request. Closes gh-22341 --- .../core/ReactiveAdapterRegistry.java | 22 ++++++++++--------- .../core/codec/AbstractEncoder.java | 9 ++++++-- .../core/log/CompositeLog.java | 9 ++++++-- .../AbstractMessageWriterResultHandler.java | 22 +++++++++++-------- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java b/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java index 4afa633d3a..48213cd343 100644 --- a/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java +++ b/spring-core/src/main/java/org/springframework/core/ReactiveAdapterRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -141,15 +141,17 @@ public class ReactiveAdapterRegistry { if (clazz == null) { return null; } - - return this.adapters.stream() - .filter(adapter -> adapter.getReactiveType() == clazz) - .findFirst() - .orElseGet(() -> - this.adapters.stream() - .filter(adapter -> adapter.getReactiveType().isAssignableFrom(clazz)) - .findFirst() - .orElse(null)); + for(ReactiveAdapter adapter : this.adapters) { + if (adapter.getReactiveType() == clazz) { + return adapter; + } + } + for(ReactiveAdapter adapter : this.adapters) { + if (adapter.getReactiveType().isAssignableFrom(clazz)) { + return adapter; + } + } + return null; } diff --git a/spring-core/src/main/java/org/springframework/core/codec/AbstractEncoder.java b/spring-core/src/main/java/org/springframework/core/codec/AbstractEncoder.java index b1d220616f..242a7bccc3 100644 --- a/spring-core/src/main/java/org/springframework/core/codec/AbstractEncoder.java +++ b/spring-core/src/main/java/org/springframework/core/codec/AbstractEncoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -74,7 +74,12 @@ public abstract class AbstractEncoder implements Encoder { if (mimeType == null) { return true; } - return this.encodableMimeTypes.stream().anyMatch(candidate -> candidate.isCompatibleWith(mimeType)); + for(MimeType candidate : this.encodableMimeTypes) { + if (candidate.isCompatibleWith(mimeType)) { + return true; + } + } + return false; } } diff --git a/spring-core/src/main/java/org/springframework/core/log/CompositeLog.java b/spring-core/src/main/java/org/springframework/core/log/CompositeLog.java index 9d46d28a95..cbdfcf9d6c 100644 --- a/spring-core/src/main/java/org/springframework/core/log/CompositeLog.java +++ b/spring-core/src/main/java/org/springframework/core/log/CompositeLog.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,7 +63,12 @@ final class CompositeLog implements Log { } private static Log initLogger(List loggers, Predicate predicate) { - return loggers.stream().filter(predicate).findFirst().orElse(NO_OP_LOG); + for (Log logger : loggers) { + if (predicate.test(logger)) { + return logger; + } + } + return NO_OP_LOG; } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java index 188cb838e9..ff0b26f0d1 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,8 @@ package org.springframework.web.reactive.result.method.annotation; +import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import org.reactivestreams.Publisher; import reactor.core.publisher.Mono; @@ -137,7 +137,8 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); - MediaType bestMediaType = selectMediaType(exchange, () -> getMediaTypesFor(elementType)); + List writableMediaTypes = getMediaTypesFor(elementType); + MediaType bestMediaType = selectMediaType(exchange, () -> writableMediaTypes); if (bestMediaType != null) { String logPrefix = exchange.getLogPrefix(); if (logger.isDebugEnabled()) { @@ -152,12 +153,12 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa } } else { - if (getMediaTypesFor(elementType).isEmpty()) { + if (writableMediaTypes.isEmpty()) { return Mono.error(new IllegalStateException("No writer for : " + elementType)); } } - return Mono.error(new NotAcceptableStatusException(getMediaTypesFor(elementType))); + return Mono.error(new NotAcceptableStatusException(writableMediaTypes)); } private ResolvableType getElementType(ReactiveAdapter adapter, ResolvableType genericType) { @@ -173,10 +174,13 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa } private List getMediaTypesFor(ResolvableType elementType) { - return getMessageWriters().stream() - .filter(converter -> converter.canWrite(elementType, null)) - .flatMap(converter -> converter.getWritableMediaTypes().stream()) - .collect(Collectors.toList()); + List writableMediaTypes = new ArrayList<>(); + for (HttpMessageWriter converter : getMessageWriters()) { + if (converter.canWrite(elementType, null)) { + writableMediaTypes.addAll(converter.getWritableMediaTypes()); + } + } + return writableMediaTypes; } }