Move HTTP exchange auto-config into appropriate modules

This commit is contained in:
Andy Wilkinson
2025-06-04 14:42:59 +01:00
committed by Phillip Webb
parent 42195163ae
commit 2f2338e57b
33 changed files with 315 additions and 239 deletions

View File

@@ -6,20 +6,6 @@
"type": "java.lang.Boolean",
"description": "Whether to enable SSL certificate health check.",
"defaultValue": true
},
{
"name": "management.httpexchanges.recording.enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable HTTP request-response exchange recording.",
"defaultValue": true
},
{
"name": "management.httpexchanges.recording.include",
"defaultValue": [
"request-headers",
"response-headers",
"errors"
]
},
{
"name": "management.otlp.tracing.export.enabled",

View File

@@ -12,5 +12,3 @@ org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryTracingAutoC
org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpTracingAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.prometheus.PrometheusExemplarsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinTracingAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesEndpointAutoConfiguration

View File

@@ -26,7 +26,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesAutoConfiguration;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
@@ -47,8 +46,7 @@ class JmxEndpointAccessIntegrationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, EndpointAutoConfiguration.class,
JmxEndpointAutoConfiguration.class, HealthContributorAutoConfiguration.class,
HttpExchangesAutoConfiguration.class))
JmxEndpointAutoConfiguration.class, HealthContributorAutoConfiguration.class))
.withUserConfiguration(CustomJmxEndpoint.class)
.withPropertyValues("spring.jmx.enabled=true")
.withConfiguration(AutoConfigurations.of(EndpointAutoConfigurationClasses.ALL));

View File

@@ -31,7 +31,6 @@ import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesAutoConfiguration;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
@@ -52,8 +51,7 @@ class JmxEndpointIntegrationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JmxAutoConfiguration.class, EndpointAutoConfiguration.class,
JmxEndpointAutoConfiguration.class, HealthContributorAutoConfiguration.class,
HttpExchangesAutoConfiguration.class))
JmxEndpointAutoConfiguration.class, HealthContributorAutoConfiguration.class))
.withUserConfiguration(HttpExchangeRepositoryConfiguration.class, AuditEventRepositoryConfiguration.class)
.withPropertyValues("spring.jmx.enabled=true")
.withConfiguration(AutoConfigurations.of(EndpointAutoConfigurationClasses.ALL));

View File

@@ -30,13 +30,13 @@ import org.springframework.boot.actuate.audit.InMemoryAuditEventRepository;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.servlet.actuate.autoconfigure.ServletManagementContextAutoConfiguration;
import org.springframework.boot.servlet.actuate.autoconfigure.exchanges.ServletHttpExchangesAutoConfiguration;
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
@@ -70,7 +70,7 @@ class WebMvcEndpointExposureIntegrationTests {
JacksonAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class,
WebMvcAutoConfiguration.class, EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
ManagementContextAutoConfiguration.class, ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class, HttpExchangesAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class, ServletHttpExchangesAutoConfiguration.class,
HealthContributorAutoConfiguration.class))
.withConfiguration(AutoConfigurations.of(EndpointAutoConfigurationClasses.ALL))
.withUserConfiguration(CustomMvcEndpoint.class, CustomServletEndpoint.class,

View File

@@ -1,161 +0,0 @@
/*
* Copyright 2012-2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.exchanges;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.Include;
import org.springframework.boot.actuate.web.exchanges.servlet.HttpExchangesFilter;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.webflux.actuate.web.exchanges.HttpExchangesWebFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link HttpExchangesAutoConfiguration}.
*
* @author Andy Wilkinson
* @author Madhura Bhave
*/
class HttpExchangesAutoConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(HttpExchangesAutoConfiguration.class));
@Test
void autoConfigurationIsDisabledByDefault() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesAutoConfiguration.class));
}
@Test
void autoConfigurationIsEnabledWhenHttpExchangeRepositoryBeanPresent() {
this.contextRunner.withUserConfiguration(CustomHttpExchangesRepositoryConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(HttpExchangesFilter.class);
assertThat(context).hasSingleBean(HttpExchangeRepository.class);
assertThat(context.getBean(HttpExchangeRepository.class)).isInstanceOf(CustomHttpExchangesRepository.class);
});
}
@Test
void usesUserProvidedWebFilterWhenReactiveContext() {
new ReactiveWebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(HttpExchangesAutoConfiguration.class))
.withUserConfiguration(CustomHttpExchangesRepositoryConfiguration.class)
.withUserConfiguration(CustomWebFilterConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(HttpExchangesWebFilter.class);
assertThat(context.getBean(HttpExchangesWebFilter.class))
.isInstanceOf(CustomHttpExchangesWebFilter.class);
});
}
@Test
void configuresServletFilter() {
this.contextRunner.withUserConfiguration(CustomHttpExchangesRepositoryConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(HttpExchangesFilter.class));
}
@Test
void usesUserProvidedServletFilter() {
this.contextRunner.withUserConfiguration(CustomHttpExchangesRepositoryConfiguration.class)
.withUserConfiguration(CustomFilterConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(HttpExchangesFilter.class);
assertThat(context.getBean(HttpExchangesFilter.class)).isInstanceOf(CustomHttpExchangesFilter.class);
});
}
@Test
void backsOffWhenNotRecording() {
this.contextRunner.withUserConfiguration(CustomHttpExchangesRepositoryConfiguration.class)
.withPropertyValues("management.httpexchanges.recording.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(InMemoryHttpExchangeRepository.class)
.doesNotHaveBean(HttpExchangesFilter.class));
}
static class CustomHttpExchangesRepository implements HttpExchangeRepository {
@Override
public List<HttpExchange> findAll() {
return null;
}
@Override
public void add(HttpExchange exchange) {
}
}
@Configuration(proxyBeanMethods = false)
static class CustomHttpExchangesRepositoryConfiguration {
@Bean
CustomHttpExchangesRepository customRepository() {
return new CustomHttpExchangesRepository();
}
}
private static final class CustomHttpExchangesWebFilter extends HttpExchangesWebFilter {
private CustomHttpExchangesWebFilter(HttpExchangeRepository repository, Set<Include> includes) {
super(repository, includes);
}
}
@Configuration(proxyBeanMethods = false)
static class CustomWebFilterConfiguration {
@Bean
CustomHttpExchangesWebFilter customWebFilter(HttpExchangeRepository repository,
HttpExchangesProperties properties) {
return new CustomHttpExchangesWebFilter(repository, properties.getRecording().getInclude());
}
}
private static final class CustomHttpExchangesFilter extends HttpExchangesFilter {
private CustomHttpExchangesFilter(HttpExchangeRepository repository, Set<Include> includes) {
super(repository, includes);
}
}
@Configuration(proxyBeanMethods = false)
static class CustomFilterConfiguration {
@Bean
CustomHttpExchangesFilter customWebFilter(HttpExchangeRepository repository, Set<Include> includes) {
return new CustomHttpExchangesFilter(repository, includes);
}
}
}

View File

@@ -32,7 +32,7 @@ import org.springframework.context.annotation.Bean;
* @author Phillip Webb
* @since 3.0.0
*/
@AutoConfiguration(after = HttpExchangesAutoConfiguration.class)
@AutoConfiguration
@ConditionalOnAvailableEndpoint(HttpExchangesEndpoint.class)
public class HttpExchangesEndpointAutoConfiguration {

View File

@@ -138,6 +138,20 @@
"description": "Whether to enable readiness state health check.",
"defaultValue": false
},
{
"name": "management.httpexchanges.recording.enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable HTTP request-response exchange recording.",
"defaultValue": true
},
{
"name": "management.httpexchanges.recording.include",
"defaultValue": [
"request-headers",
"response-headers",
"errors"
]
},
{
"name": "management.info.build.enabled",
"type": "java.lang.Boolean",

View File

@@ -23,5 +23,6 @@ org.springframework.boot.actuate.autoconfigure.sbom.SbomEndpointAutoConfiguratio
org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.startup.StartupEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.mappings.MappingsEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration

View File

@@ -35,8 +35,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
class HttpExchangesEndpointAutoConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner().withConfiguration(
AutoConfigurations.of(HttpExchangesAutoConfiguration.class, HttpExchangesEndpointAutoConfiguration.class));
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(HttpExchangesEndpointAutoConfiguration.class));
@Test
void runWhenRepositoryBeanAvailableShouldHaveEndpointBean() {

View File

@@ -14,11 +14,11 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.exchanges;
package org.springframework.boot.servlet.actuate.autoconfigure.exchanges;
import org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesProperties;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.servlet.HttpExchangesFilter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -27,47 +27,27 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.webflux.actuate.web.exchanges.HttpExchangesWebFilter;
import org.springframework.boot.servlet.actuate.exchanges.HttpExchangesFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link EnableAutoConfiguration Auto-configuration} to record {@link HttpExchange HTTP
* exchanges}.
*
* @author Dave Syer
* @since 3.0.0
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnWebApplication
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnBooleanProperty(name = "management.httpexchanges.recording.enabled", matchIfMissing = true)
@ConditionalOnBean(HttpExchangeRepository.class)
@EnableConfigurationProperties(HttpExchangesProperties.class)
public class HttpExchangesAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
static class ServletHttpExchangesConfiguration {
@Bean
@ConditionalOnMissingBean
HttpExchangesFilter httpExchangesFilter(HttpExchangeRepository repository, HttpExchangesProperties properties) {
return new HttpExchangesFilter(repository, properties.getRecording().getInclude());
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.REACTIVE)
static class ReactiveHttpExchangesConfiguration {
@Bean
@ConditionalOnMissingBean
HttpExchangesWebFilter httpExchangesWebFilter(HttpExchangeRepository repository,
HttpExchangesProperties properties) {
return new HttpExchangesWebFilter(repository, properties.getRecording().getInclude());
}
public class ServletHttpExchangesAutoConfiguration {
@Bean
@ConditionalOnMissingBean
HttpExchangesFilter httpExchangesFilter(HttpExchangeRepository repository, HttpExchangesProperties properties) {
return new HttpExchangesFilter(repository, properties.getRecording().getInclude());
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2012-2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Auto-configuration for Servlet-based integration with Actuator's HTTP exchanges
* support.
*/
package org.springframework.boot.servlet.actuate.autoconfigure.exchanges;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web.exchanges.servlet;
package org.springframework.boot.servlet.actuate.exchanges;
import java.io.IOException;
import java.net.URI;
@@ -43,7 +43,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
* @author Andy Wilkinson
* @author Venil Noronha
* @author Madhura Bhave
* @since 3.0.0
* @since 4.0.0
*/
public class HttpExchangesFilter extends OncePerRequestFilter implements Ordered {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web.exchanges.servlet;
package org.springframework.boot.servlet.actuate.exchanges;
import java.net.URI;
import java.net.URISyntaxException;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web.exchanges.servlet;
package org.springframework.boot.servlet.actuate.exchanges;
import java.util.ArrayList;
import java.util.LinkedHashMap;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2025 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.
@@ -15,8 +15,8 @@
*/
/**
* Actuator HTTP exchanges support for servlet servers.
* Actuator HTTP exchanges support for Servlet servers.
*
* @see org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository
*/
package org.springframework.boot.actuate.web.exchanges.servlet;
package org.springframework.boot.servlet.actuate.exchanges;

View File

@@ -1,3 +1,4 @@
org.springframework.boot.servlet.actuate.autoconfigure.ServletManagementContextAutoConfiguration
org.springframework.boot.servlet.actuate.autoconfigure.exchanges.ServletHttpExchangesAutoConfiguration
org.springframework.boot.servlet.actuate.autoconfigure.mappings.ServletMappingsAutoConfiguration
org.springframework.boot.servlet.autoconfigure.MultipartAutoConfiguration

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2012-2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.servlet.actuate.autoconfigure.exchanges;
import java.util.EnumSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.Include;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.servlet.actuate.exchanges.HttpExchangesFilter;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ServletHttpExchangesAutoConfiguration}.
*
* @author Andy Wilkinson
*/
class ServletHttpExchangesAutoConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ServletHttpExchangesAutoConfiguration.class));
@Test
void whenRecordingIsDisabledThenFilterIsNotCreated() {
this.contextRunner.withBean(InMemoryHttpExchangeRepository.class)
.withPropertyValues("management.httpexchanges.recording.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesFilter.class));
}
@Test
void whenNoRepositoryIsDefinedThenFilterIsNotCreated() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesFilter.class));
}
@Test
void filterIsCreated() {
this.contextRunner.withBean(InMemoryHttpExchangeRepository.class)
.run((context) -> assertThat(context).hasSingleBean(HttpExchangesFilter.class));
}
@Test
void usesUserProvidedWebFilter() {
InMemoryHttpExchangeRepository repository = new InMemoryHttpExchangeRepository();
this.contextRunner.withBean(InMemoryHttpExchangeRepository.class, () -> repository)
.withBean(CustomHttpExchangesFilter.class,
() -> new CustomHttpExchangesFilter(repository, EnumSet.allOf(Include.class)))
.run((context) -> {
assertThat(context).hasSingleBean(HttpExchangesFilter.class);
assertThat(context.getBean(HttpExchangesFilter.class)).isInstanceOf(CustomHttpExchangesFilter.class);
});
}
private static final class CustomHttpExchangesFilter extends HttpExchangesFilter {
private CustomHttpExchangesFilter(HttpExchangeRepository repository, Set<Include> includes) {
super(repository, includes);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web.exchanges.servlet;
package org.springframework.boot.servlet.actuate.exchanges;
import java.io.IOException;
import java.security.Principal;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2025 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web.exchanges.servlet;
package org.springframework.boot.servlet.actuate.exchanges;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2012-2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.webflux.actuate.autoconfigure.exchanges;
import org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesProperties;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.webflux.actuate.exchanges.HttpExchangesWebFilter;
import org.springframework.context.annotation.Bean;
/**
* {@link EnableAutoConfiguration Auto-configuration} to record {@link HttpExchange HTTP
* exchanges}.
*
* @author Dave Syer
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnWebApplication(type = Type.REACTIVE)
@ConditionalOnBooleanProperty(name = "management.httpexchanges.recording.enabled", matchIfMissing = true)
@ConditionalOnBean(HttpExchangeRepository.class)
@EnableConfigurationProperties(HttpExchangesProperties.class)
public class WebFluxHttpExchangesAutoConfiguration {
@Bean
@ConditionalOnMissingBean
HttpExchangesWebFilter httpExchangesWebFilter(HttpExchangeRepository repository,
HttpExchangesProperties properties) {
return new HttpExchangesWebFilter(repository, properties.getRecording().getInclude());
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2012-2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Auto-configuration for WebFlux-based integration with Actuator's HTTP exchanges
* support.
*/
package org.springframework.boot.webflux.actuate.autoconfigure.exchanges;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.webflux.actuate.web.exchanges;
package org.springframework.boot.webflux.actuate.exchanges;
import java.security.Principal;
import java.util.Set;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.webflux.actuate.web.exchanges;
package org.springframework.boot.webflux.actuate.exchanges;
import java.net.InetAddress;
import java.net.InetSocketAddress;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.webflux.actuate.web.exchanges;
package org.springframework.boot.webflux.actuate.exchanges;
import java.util.Collections;
import java.util.LinkedHashMap;

View File

@@ -19,4 +19,4 @@
*
* @see org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository
*/
package org.springframework.boot.webflux.actuate.web.exchanges;
package org.springframework.boot.webflux.actuate.exchanges;

View File

@@ -1,3 +1,4 @@
org.springframework.boot.webflux.actuate.autoconfigure.exchanges.WebFluxHttpExchangesAutoConfiguration
org.springframework.boot.webflux.actuate.autoconfigure.health.WebFluxHealthEndpointExtensionAutoConfiguration
org.springframework.boot.webflux.actuate.autoconfigure.mappings.WebFluxMappingsAutoConfiguration
org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration
@@ -5,4 +6,4 @@ org.springframework.boot.webflux.autoconfigure.ReactiveMultipartAutoConfiguratio
org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration
org.springframework.boot.webflux.autoconfigure.WebSessionIdResolverAutoConfiguration
org.springframework.boot.webflux.autoconfigure.error.ErrorWebFluxAutoConfiguration
org.springframework.boot.webflux.observation.autoconfigure.WebFluxObservationAutoConfiguration
org.springframework.boot.webflux.observation.autoconfigure.WebFluxObservationAutoConfiguration

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2012-2025 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.webflux.actuate.autoconfigure.exchanges;
import java.util.EnumSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.InMemoryHttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.Include;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.webflux.actuate.exchanges.HttpExchangesWebFilter;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WebFluxHttpExchangesAutoConfiguration}.
*
* @author Andy Wilkinson
* @author Madhura Bhave
*/
class WebFluxHttpExchangesAutoConfigurationTests {
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(WebFluxHttpExchangesAutoConfiguration.class));
@Test
void whenRecordingIsDisabledThenFilterIsNotCreated() {
this.contextRunner.withBean(InMemoryHttpExchangeRepository.class)
.withPropertyValues("management.httpexchanges.recording.enabled=false")
.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesWebFilter.class));
}
@Test
void whenNoRepositoryIsDefinedThenFilterIsNotCreated() {
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(HttpExchangesWebFilter.class));
}
@Test
void filterIsCreated() {
this.contextRunner.withBean(InMemoryHttpExchangeRepository.class)
.run((context) -> assertThat(context).hasSingleBean(HttpExchangesWebFilter.class));
}
@Test
void usesUserProvidedWebFilter() {
InMemoryHttpExchangeRepository repository = new InMemoryHttpExchangeRepository();
this.contextRunner.withBean(InMemoryHttpExchangeRepository.class, () -> repository)
.withBean(CustomHttpExchangesWebFilter.class,
() -> new CustomHttpExchangesWebFilter(repository, EnumSet.allOf(Include.class)))
.run((context) -> {
assertThat(context).hasSingleBean(HttpExchangesWebFilter.class);
assertThat(context.getBean(HttpExchangesWebFilter.class))
.isInstanceOf(CustomHttpExchangesWebFilter.class);
});
}
private static final class CustomHttpExchangesWebFilter extends HttpExchangesWebFilter {
private CustomHttpExchangesWebFilter(HttpExchangeRepository repository, Set<Include> includes) {
super(repository, includes);
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.webflux.actuate.web.exchanges;
package org.springframework.boot.webflux.actuate.exchanges;
import java.util.EnumSet;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.webflux.actuate.web.exchanges;
package org.springframework.boot.webflux.actuate.exchanges;
import java.security.Principal;
import java.time.Duration;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.webflux.actuate.web.exchanges;
package org.springframework.boot.webflux.actuate.exchanges;
import java.net.InetSocketAddress;
import java.net.URI;