Skip to content

Commit b7f59eb

Browse files
committed
Add config property for webflux codec maxInMemorySize
This commit creates a new configuration property `spring.codec.max-in-memory-size` which configures the maximum amount of data to be buffered in memory by codecs (both client and server). This property has no default value - it will let Spring Framework handle the default behavior, currently enforcing a 256KB for provided codecs. Fixes gh-18828
1 parent 2d0a235 commit b7f59eb

File tree

6 files changed

+98
-12
lines changed

6 files changed

+98
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.autoconfigure.codec;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
import org.springframework.util.unit.DataSize;
21+
22+
/**
23+
* {@link ConfigurationProperties properties} for reactive codecs.
24+
*
25+
* @author Brian Clozel
26+
* @since 2.2.1
27+
*/
28+
@ConfigurationProperties(prefix = "spring.codec")
29+
public class CodecProperties {
30+
31+
/**
32+
* Limit on the number of bytes that can be buffered whenever the input stream needs
33+
* to be aggregated. By default this is not set, in which case individual codec
34+
* defaults apply. Most codecs are limited to 256K by default.
35+
*/
36+
private DataSize maxInMemorySize;
37+
38+
public DataSize getMaxInMemorySize() {
39+
return this.maxInMemorySize;
40+
}
41+
42+
public void setMaxInMemorySize(DataSize maxInMemorySize) {
43+
this.maxInMemorySize = maxInMemorySize;
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Auto-configuration for reactive codecs.
19+
*/
20+
package org.springframework.boot.autoconfigure.codec;

Diff for: spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfiguration.java

+13-5
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020

2121
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2222
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
23+
import org.springframework.boot.autoconfigure.codec.CodecProperties;
2324
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2425
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2526
import org.springframework.boot.autoconfigure.http.HttpProperties;
2627
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
2728
import org.springframework.boot.context.properties.EnableConfigurationProperties;
29+
import org.springframework.boot.context.properties.PropertyMapper;
2830
import org.springframework.boot.web.codec.CodecCustomizer;
2931
import org.springframework.context.annotation.Bean;
3032
import org.springframework.context.annotation.Configuration;
@@ -33,6 +35,7 @@
3335
import org.springframework.http.codec.json.Jackson2JsonDecoder;
3436
import org.springframework.http.codec.json.Jackson2JsonEncoder;
3537
import org.springframework.util.MimeType;
38+
import org.springframework.util.unit.DataSize;
3639
import org.springframework.web.reactive.function.client.WebClient;
3740

3841
/**
@@ -46,6 +49,7 @@
4649
@Configuration(proxyBeanMethods = false)
4750
@ConditionalOnClass({ CodecConfigurer.class, WebClient.class })
4851
@AutoConfigureAfter(JacksonAutoConfiguration.class)
52+
@EnableConfigurationProperties({ HttpProperties.class, CodecProperties.class })
4953
public class CodecsAutoConfiguration {
5054

5155
private static final MimeType[] EMPTY_MIME_TYPES = {};
@@ -68,14 +72,18 @@ CodecCustomizer jacksonCodecCustomizer(ObjectMapper objectMapper) {
6872
}
6973

7074
@Configuration(proxyBeanMethods = false)
71-
@EnableConfigurationProperties(HttpProperties.class)
72-
static class LoggingCodecConfiguration {
75+
static class DefaultCodecsConfiguration {
7376

7477
@Bean
7578
@Order(0)
76-
CodecCustomizer loggingCodecCustomizer(HttpProperties properties) {
77-
return (configurer) -> configurer.defaultCodecs()
78-
.enableLoggingRequestDetails(properties.isLogRequestDetails());
79+
CodecCustomizer defaultCodecCustomizer(HttpProperties httpProperties, CodecProperties codecProperties) {
80+
return (configurer) -> {
81+
PropertyMapper map = PropertyMapper.get();
82+
CodecConfigurer.DefaultCodecs defaultCodecs = configurer.defaultCodecs();
83+
defaultCodecs.enableLoggingRequestDetails(httpProperties.isLogRequestDetails());
84+
map.from(codecProperties.getMaxInMemorySize()).whenNonNull().asInt(DataSize::toBytes)
85+
.to(defaultCodecs::maxInMemorySize);
86+
};
7987
}
8088

8189
}

Diff for: spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/http/codec/CodecsAutoConfigurationTests.java

+14-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.junit.jupiter.api.Test;
2323

2424
import org.springframework.boot.autoconfigure.AutoConfigurations;
25+
import org.springframework.boot.autoconfigure.codec.CodecProperties;
2526
import org.springframework.boot.autoconfigure.http.HttpProperties;
2627
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
2728
import org.springframework.boot.web.codec.CodecCustomizer;
@@ -67,11 +68,11 @@ void loggingRequestDetailsCustomizerShouldUseHttpProperties() {
6768
}
6869

6970
@Test
70-
void loggingRequestDetailsBeanShouldHaveOrderZero() {
71+
void defaultCodecCustomizerBeanShouldHaveOrderZero() {
7172
this.contextRunner.run((context) -> {
7273
Method customizerMethod = ReflectionUtils.findMethod(
73-
CodecsAutoConfiguration.LoggingCodecConfiguration.class, "loggingCodecCustomizer",
74-
HttpProperties.class);
74+
CodecsAutoConfiguration.DefaultCodecsConfiguration.class, "defaultCodecCustomizer",
75+
HttpProperties.class, CodecProperties.class);
7576
Integer order = new TestAnnotationAwareOrderComparator().findOrder(customizerMethod);
7677
assertThat(order).isEqualTo(0);
7778
});
@@ -98,6 +99,16 @@ void userProvidedCustomizerCanOverrideJacksonCodecCustomizer() {
9899
});
99100
}
100101

102+
@Test
103+
void maxInMemorySizeEnforcedInDefaultCodecs() {
104+
this.contextRunner.withPropertyValues("spring.codec.max-in-memory-size=1MB").run((context) -> {
105+
CodecCustomizer customizer = context.getBean(CodecCustomizer.class);
106+
CodecConfigurer configurer = new DefaultClientCodecConfigurer();
107+
customizer.customize(configurer);
108+
assertThat(configurer.defaultCodecs()).hasFieldOrPropertyWithValue("maxInMemorySize", 1048576);
109+
});
110+
}
111+
101112
static class TestAnnotationAwareOrderComparator extends AnnotationAwareOrderComparator {
102113

103114
@Override

Diff for: spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

+4-3
Original file line numberDiff line numberDiff line change
@@ -2538,8 +2538,9 @@ If you want to take complete control of Spring WebFlux, you can add your own `@C
25382538
Spring WebFlux uses the `HttpMessageReader` and `HttpMessageWriter` interfaces to convert HTTP requests and responses.
25392539
They are configured with `CodecConfigurer` to have sensible defaults by looking at the libraries available in your classpath.
25402540

2541-
Spring Boot applies further customization by using `CodecCustomizer` instances.
2542-
For example, `spring.jackson.*` configuration keys are applied to the Jackson codec.
2541+
Spring Boot provides dedicated configuration properties for codecs, `+spring.codec.*+`.
2542+
It also applies further customization by using `CodecCustomizer` instances.
2543+
For example, `+spring.jackson.*+` configuration keys are applied to the Jackson codec.
25432544

25442545
If you need to add or customize codecs, you can create a custom `CodecCustomizer` component, as shown in the following example:
25452546

@@ -2554,7 +2555,7 @@ If you need to add or customize codecs, you can create a custom `CodecCustomizer
25542555
public CodecCustomizer myCodecCustomizer() {
25552556
return codecConfigurer -> {
25562557
// ...
2557-
}
2558+
};
25582559
}
25592560
25602561
}

Diff for: spring-boot-project/spring-boot-docs/src/main/groovy/generateConfigurationPropertyTables.groovy

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def generateConfigMetadataDocumentation() {
2424
builder
2525
.addSection("core")
2626
.withKeyPrefixes("debug", "trace", "logging", "spring.aop", "spring.application",
27-
"spring.autoconfigure", "spring.banner", "spring.beaninfo", "spring.config",
27+
"spring.autoconfigure", "spring.banner", "spring.beaninfo", "spring.codec", "spring.config",
2828
"spring.info", "spring.jmx", "spring.main", "spring.messages", "spring.pid",
2929
"spring.profiles", "spring.quartz", "spring.reactor", "spring.task",
3030
"spring.mandatory-file-encoding", "info", "spring.output.ansi.enabled")

0 commit comments

Comments
 (0)