Move Actuator infrastructure for WebFlux to spring-boot-webflux

This commit is contained in:
Stéphane Nicoll
2025-05-30 12:06:09 +02:00
committed by Phillip Webb
parent b9aa01c1c4
commit e0a6237b8a
41 changed files with 250 additions and 116 deletions

View File

@@ -41,7 +41,7 @@ import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping;
import org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

View File

@@ -18,7 +18,6 @@ package org.springframework.boot.actuate.autoconfigure.web.exchanges;
import org.springframework.boot.actuate.web.exchanges.HttpExchange;
import org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository;
import org.springframework.boot.actuate.web.exchanges.reactive.HttpExchangesWebFilter;
import org.springframework.boot.actuate.web.exchanges.servlet.HttpExchangesFilter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@@ -28,6 +27,7 @@ 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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

View File

@@ -1,3 +1 @@
org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.security.servlet.SecurityRequestMatchersManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementChildContextConfiguration

View File

@@ -23,7 +23,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.http.codec.autoconfigure.CodecsAutoConfiguration;
@@ -31,6 +30,7 @@ import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.web.context.reactive.ReactiveWebApplicationContext;
import org.springframework.boot.webflux.actuate.autoconfigure.endpoint.web.WebFluxEndpointManagementContextConfiguration;
import org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;
import org.springframework.http.HttpHeaders;

View File

@@ -32,6 +32,7 @@ import org.springframework.boot.test.context.runner.ReactiveWebApplicationContex
import org.springframework.boot.web.context.reactive.ConfigurableReactiveWebApplicationContext;
import org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;
import org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.webflux.actuate.autoconfigure.health.WebFluxHealthEndpointExtensionAutoConfiguration;
import org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;
@@ -47,9 +48,9 @@ class WebFluxHealthEndpointAdditionalPathIntegrationTests extends
super(new ReactiveWebApplicationContextRunner(AnnotationConfigReactiveWebServerApplicationContext::new)
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, CodecsAutoConfiguration.class,
WebFluxAutoConfiguration.class, HttpHandlerAutoConfiguration.class, EndpointAutoConfiguration.class,
HealthEndpointAutoConfiguration.class, DiskSpaceHealthContributorAutoConfiguration.class,
WebEndpointAutoConfiguration.class, ManagementContextAutoConfiguration.class,
NettyReactiveWebServerAutoConfiguration.class,
HealthEndpointAutoConfiguration.class, WebFluxHealthEndpointExtensionAutoConfiguration.class,
DiskSpaceHealthContributorAutoConfiguration.class, WebEndpointAutoConfiguration.class,
ManagementContextAutoConfiguration.class, NettyReactiveWebServerAutoConfiguration.class,
NettyReactiveManagementContextAutoConfiguration.class, BeansEndpointAutoConfiguration.class))
.withInitializer(new ServerPortInfoApplicationContextInitializer())
.withPropertyValues("server.port=0"));

View File

@@ -25,11 +25,11 @@ 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.reactive.HttpExchangesWebFilter;
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;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 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.
@@ -16,15 +16,8 @@
package org.springframework.boot.actuate.autoconfigure.health;
import java.util.Collection;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.endpoint.web.reactive.AdditionalHealthEndpointPathsWebFluxHandlerMapping;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
import org.springframework.boot.actuate.health.ReactiveHealthContributorRegistry;
@@ -58,21 +51,4 @@ class HealthEndpointReactiveWebExtensionConfiguration {
properties.getLogging().getSlowIndicatorThreshold());
}
@Configuration(proxyBeanMethods = false)
static class WebFluxAdditionalHealthEndpointPathsConfiguration {
@Bean
AdditionalHealthEndpointPathsWebFluxHandlerMapping healthEndpointWebFluxHandlerMapping(
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
ExposableWebEndpoint health = webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
.findFirst()
.orElse(null);
return new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(""), health,
groups.getAllWithAdditionalPath(WebServerNamespace.SERVER));
}
}
}

View File

@@ -24,14 +24,11 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.WithTestEndpointOutcomeExposureContributor;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointConfiguration.HealthEndpointGroupMembershipValidator.NoSuchHealthContributorException;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointReactiveWebExtensionConfiguration.WebFluxAdditionalHealthEndpointPathsConfiguration;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.health.CompositeHealthContributor;
import org.springframework.boot.actuate.health.DefaultHealthContributorRegistry;
@@ -340,23 +337,6 @@ class HealthEndpointAutoConfigurationTests {
}));
}
@Test
@WithTestEndpointOutcomeExposureContributor
void additionalReactiveHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {
this.reactiveContextRunner
.withConfiguration(
AutoConfigurations.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))
.withPropertyValues("management.endpoints.web.exposure.exclude=*",
"management.endpoints.test.exposure.include=*")
.run((context) -> {
assertThat(context).hasNotFailed();
assertThat(context).hasSingleBean(HealthEndpoint.class);
assertThat(context).hasSingleBean(ReactiveHealthEndpointWebExtension.class);
assertThat(context.getBean(WebEndpointsSupplier.class).getEndpoints()).isEmpty();
assertThat(context).hasSingleBean(WebFluxAdditionalHealthEndpointPathsConfiguration.class);
});
}
@Configuration(proxyBeanMethods = false)
static class HealthIndicatorsConfiguration {

View File

@@ -31,13 +31,13 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.jackson.JacksonEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.docs.AbstractEndpointDocumentationTests.BaseDocumentationConfiguration;
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.webflux.actuate.autoconfigure.endpoint.web.WebFluxEndpointManagementContextConfiguration;
import org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;
import org.springframework.boot.webmvc.actuate.autoconfigure.endpoint.web.WebMvcEndpointManagementContextConfiguration;

View File

@@ -38,6 +38,7 @@ import org.springframework.boot.test.context.assertj.AssertableReactiveWebApplic
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.webflux.actuate.endpoint.web.ControllerEndpointHandlerMapping;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

View File

@@ -29,6 +29,7 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.server.reactive.context.ReactiveWebServerInitializedEvent;
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;
import org.springframework.boot.webflux.autoconfigure.error.ErrorWebFluxAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;

View File

@@ -37,7 +37,6 @@ dependencies {
optional("org.springframework:spring-context-support")
optional("org.springframework:spring-jdbc")
optional("org.springframework:spring-messaging")
optional("org.springframework:spring-webflux")
optional("org.springframework.graphql:spring-graphql")
optional("org.springframework.security:spring-security-core")
optional("org.springframework.security:spring-security-web")
@@ -45,6 +44,7 @@ dependencies {
testFixturesApi("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
testFixturesImplementation("org.junit.jupiter:junit-jupiter-api")
testFixturesImplementation("org.springframework:spring-test")
testFixturesImplementation("org.springframework:spring-webflux")
testImplementation(project(":spring-boot-project:spring-boot-autoconfigure"))
testImplementation(project(":spring-boot-project:spring-boot-jackson"))

View File

@@ -269,7 +269,7 @@ When it does so, the orders shown in the following table will be used:
| javadoc:org.springframework.security.web.server.WebFilterChainProxy[] (Spring Security)
| `-100`
| javadoc:org.springframework.boot.actuate.web.exchanges.reactive.HttpExchangesWebFilter[]
| javadoc:org.springframework.boot.webflux.actuate.web.exchanges.HttpExchangesWebFilter[]
| `Ordered.LOWEST_PRECEDENCE - 10`
|===

View File

@@ -16,11 +16,13 @@ dependencies {
implementation(project(":spring-boot-project:spring-boot-http-codec"))
implementation(project(":spring-boot-project:spring-boot-web-server"))
optional(project(":spring-boot-project:spring-boot-actuator"))
optional(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
optional(project(":spring-boot-project:spring-boot-metrics"))
optional(project(":spring-boot-project:spring-boot-observation"))
optional(project(":spring-boot-project:spring-boot-validation"))
optional("com.fasterxml.jackson.core:jackson-databind")
optional("org.springframework.security:spring-security-core")
testFixturesApi(testFixtures(project(":spring-boot-project:spring-boot-actuator")))
testFixturesImplementation(project(":spring-boot-project:spring-boot-jackson"))
@@ -29,8 +31,11 @@ dependencies {
testImplementation(project(":spring-boot-project:spring-boot-mustache"))
testImplementation(project(":spring-boot-project:spring-boot-reactor-netty"))
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tomcat"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-actuator-autoconfigure")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-web-server")))
testImplementation("io.projectreactor:reactor-test")
testImplementation("org.aspectj:aspectjweaver")
testRuntimeOnly("ch.qos.logback:logback-classic")

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.autoconfigure.endpoint.web;
import java.util.ArrayList;
import java.util.Arrays;
@@ -47,8 +47,6 @@ import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.endpoint.web.reactive.AdditionalHealthEndpointPathsWebFluxHandlerMapping;
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@@ -57,6 +55,8 @@ 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.endpoint.web.AdditionalHealthEndpointPathsWebFluxHandlerMapping;
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Role;
import org.springframework.core.codec.Encoder;
@@ -128,12 +128,12 @@ public class WebFluxEndpointManagementContextConfiguration {
@ConditionalOnMissingBean
@SuppressWarnings("removal")
@Deprecated(since = "3.3.5", forRemoval = true)
public org.springframework.boot.actuate.endpoint.web.reactive.ControllerEndpointHandlerMapping controllerEndpointHandlerMapping(
public org.springframework.boot.webflux.actuate.endpoint.web.ControllerEndpointHandlerMapping controllerEndpointHandlerMapping(
org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier controllerEndpointsSupplier,
CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties,
EndpointAccessResolver endpointAccessResolver) {
EndpointMapping endpointMapping = new EndpointMapping(webEndpointProperties.getBasePath());
return new org.springframework.boot.actuate.endpoint.web.reactive.ControllerEndpointHandlerMapping(
return new org.springframework.boot.webflux.actuate.endpoint.web.ControllerEndpointHandlerMapping(
endpointMapping, controllerEndpointsSupplier.getEndpoints(), corsProperties.toCorsConfiguration(),
endpointAccessResolver);
}

View File

@@ -17,4 +17,4 @@
/**
* Auto-configuration for exposing actuator web endpoints using WebFlux.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.autoconfigure.endpoint.web;

View File

@@ -0,0 +1,62 @@
/*
* 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.health;
import java.util.Collection;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.webflux.actuate.endpoint.web.AdditionalHealthEndpointPathsWebFluxHandlerMapping;
import org.springframework.context.annotation.Bean;
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link HealthEndpoint} web
* extension with Spring WebFlux.
*
* @author Stephane Nicoll
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnWebApplication(type = Type.REACTIVE)
@ConditionalOnClass(HealthEndpoint.class)
@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)
public class WebFluxHealthEndpointExtensionAutoConfiguration {
@Bean
AdditionalHealthEndpointPathsWebFluxHandlerMapping healthEndpointWebFluxHandlerMapping(
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
ExposableWebEndpoint health = webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
.findFirst()
.orElse(null);
return new AdditionalHealthEndpointPathsWebFluxHandlerMapping(new EndpointMapping(""), health,
groups.getAllWithAdditionalPath(WebServerNamespace.SERVER));
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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 actuator health concerns using Spring WebFlux.
*/
package org.springframework.boot.webflux.actuate.autoconfigure.health;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.reactive;
package org.springframework.boot.webflux.actuate.autoconfigure.web;
import java.util.Collections;
import java.util.Map;
@@ -24,6 +24,7 @@ import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfi
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextType;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementWebServerFactoryCustomizer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
@@ -32,6 +33,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.http.server.reactive.ContextPathCompositeHandler;
import org.springframework.http.server.reactive.HttpHandler;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.DispatcherHandler;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
@@ -43,21 +45,21 @@ import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
* @author Andy Wilkinson
* @author Phillip Webb
* @author Moritz Halbritter
* @since 2.0.0
*/
@EnableWebFlux
@ManagementContextConfiguration(value = ManagementContextType.CHILD, proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.REACTIVE)
public class ReactiveManagementChildContextConfiguration {
@ConditionalOnClass(DispatcherHandler.class)
@EnableWebFlux
class WebFluxManagementChildContextConfiguration {
@Bean
public ManagementWebServerFactoryCustomizer<ConfigurableWebServerFactory> reactiveManagementWebServerFactoryCustomizer(
ManagementWebServerFactoryCustomizer<ConfigurableWebServerFactory> reactiveManagementWebServerFactoryCustomizer(
ListableBeanFactory beanFactory) {
return new ManagementWebServerFactoryCustomizer<>(beanFactory);
}
@Bean
public HttpHandler httpHandler(ApplicationContext applicationContext, ManagementServerProperties properties) {
HttpHandler httpHandler(ApplicationContext applicationContext, ManagementServerProperties properties) {
HttpHandler httpHandler = WebHttpHandlerBuilder.applicationContext(applicationContext).build();
if (StringUtils.hasText(properties.getBasePath())) {
Map<String, HttpHandler> handlersMap = Collections.singletonMap(properties.getBasePath(), httpHandler);

View File

@@ -17,4 +17,4 @@
/**
* Configuration for a WebFlux-based management context.
*/
package org.springframework.boot.actuate.autoconfigure.web.reactive;
package org.springframework.boot.webflux.actuate.autoconfigure.web;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.endpoint.web;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
@@ -49,8 +49,8 @@ import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.WebOperationRequestPredicate;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.AbstractWebFluxEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.web.server.context.WebServerApplicationContext;
import org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.AbstractWebFluxEndpointHandlerMappingRuntimeHints;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
@@ -85,7 +85,7 @@ import org.springframework.web.util.pattern.PathPattern;
* @author Phillip Webb
* @author Brian Clozel
* @author Scott Frederick
* @since 2.0.0
* @since 4.0.0
*/
@ImportRuntimeHints(AbstractWebFluxEndpointHandlerMappingRuntimeHints.class)
public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappingInfoHandlerMapping {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 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.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.endpoint.web;
import java.util.Collection;
import java.util.Collections;
@@ -36,7 +36,7 @@ import org.springframework.web.reactive.result.method.RequestMappingInfo;
* path.
*
* @author Madhura Bhave
* @since 2.6.0
* @since 4.0.0
*/
public class AdditionalHealthEndpointPathsWebFluxHandlerMapping extends AbstractWebFluxEndpointHandlerMapping {

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.endpoint.web;
import java.lang.reflect.Method;
import java.util.Collection;
@@ -46,7 +46,7 @@ import org.springframework.web.util.pattern.PathPattern;
* annotated endpoints over Spring WebFlux.
*
* @author Phillip Webb
* @since 2.0.0
* @since 4.0.0
* @deprecated since 3.3.5 in favor of {@code @Endpoint} and {@code @WebEndpoint} support
*/
@Deprecated(since = "3.3.5", forRemoval = true)

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.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.endpoint.web;
import java.util.Collection;
import java.util.Collections;
@@ -32,7 +32,7 @@ import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping.WebFluxEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping.WebFluxEndpointHandlerMappingRuntimeHints;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.cors.CorsConfiguration;
@@ -47,7 +47,7 @@ import org.springframework.web.util.UriComponentsBuilder;
* @author Andy Wilkinson
* @author Phillip Webb
* @author Brian Clozel
* @since 2.0.0
* @since 4.0.0
*/
@ImportRuntimeHints(WebFluxEndpointHandlerMappingRuntimeHints.class)
public class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandlerMapping implements InitializingBean {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 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.
@@ -17,4 +17,4 @@
/**
* Spring WebFlux support for actuator endpoints.
*/
package org.springframework.boot.actuate.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.endpoint.web;

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.reactive;
package org.springframework.boot.webflux.actuate.web.exchanges;
import java.security.Principal;
import java.util.Set;

View File

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

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.web.exchanges.reactive;
package org.springframework.boot.webflux.actuate.web.exchanges;
import java.util.Collections;
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.
@@ -19,4 +19,4 @@
*
* @see org.springframework.boot.actuate.web.exchanges.HttpExchangeRepository
*/
package org.springframework.boot.actuate.web.exchanges.reactive;
package org.springframework.boot.webflux.actuate.web.exchanges;

View File

@@ -0,0 +1,2 @@
org.springframework.boot.webflux.actuate.autoconfigure.endpoint.web.WebFluxEndpointManagementContextConfiguration
org.springframework.boot.webflux.actuate.autoconfigure.web.WebFluxManagementChildContextConfiguration

View File

@@ -1,3 +1,4 @@
org.springframework.boot.webflux.actuate.autoconfigure.health.WebFluxHealthEndpointExtensionAutoConfiguration
org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration
org.springframework.boot.webflux.autoconfigure.ReactiveMultipartAutoConfiguration
org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration

View File

@@ -0,0 +1,85 @@
/*
* 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.health;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.WithTestEndpointOutcomeExposureContributor;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthContributorAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.ReactiveHealthEndpointWebExtension;
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.boot.webflux.actuate.endpoint.web.AdditionalHealthEndpointPathsWebFluxHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WebFluxHealthEndpointExtensionAutoConfiguration}.
*
* @author Stephane Nicoll
*/
class WebFluxHealthEndpointExtensionAutoConfigurationTests {
private final ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner()
.withUserConfiguration(HealthIndicatorsConfiguration.class)
.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,
HealthEndpointAutoConfiguration.class, WebFluxHealthEndpointExtensionAutoConfiguration.class));
@Test
@WithTestEndpointOutcomeExposureContributor
void additionalReactiveHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {
this.contextRunner
.withConfiguration(
AutoConfigurations.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))
.withPropertyValues("management.endpoints.web.exposure.exclude=*",
"management.endpoints.test.exposure.include=*")
.run((context) -> {
assertThat(context).hasNotFailed();
assertThat(context).hasSingleBean(HealthEndpoint.class);
assertThat(context).hasSingleBean(ReactiveHealthEndpointWebExtension.class);
assertThat(context.getBean(WebEndpointsSupplier.class).getEndpoints()).isEmpty();
assertThat(context).hasSingleBean(AdditionalHealthEndpointPathsWebFluxHandlerMapping.class);
});
}
@Configuration(proxyBeanMethods = false)
static class HealthIndicatorsConfiguration {
@Bean
ReactiveHealthIndicator simpleHealthIndicator() {
return () -> Mono.just(Health.up().build());
}
@Bean
HealthIndicator additionalHealthIndicator() {
return () -> Health.up().build();
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.reactive;
package org.springframework.boot.webflux.actuate.autoconfigure.web;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -59,11 +59,11 @@ import org.springframework.web.reactive.function.client.WebClient;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for {@link ReactiveManagementChildContextConfiguration}.
* Integration tests for {@link WebFluxManagementChildContextConfiguration}.
*
* @author Andy Wilkinson
*/
class ReactiveManagementChildContextConfigurationIntegrationTests {
class WebFluxManagementChildContextConfigurationIntegrationTests {
private final List<WebServer> webServers = new ArrayList<>();

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.reactive;
package org.springframework.boot.webflux.actuate.autoconfigure.web;
import org.junit.jupiter.api.Test;
@@ -24,18 +24,18 @@ import org.springframework.boot.test.context.runner.ReactiveWebApplicationContex
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ReactiveManagementChildContextConfiguration}.
* Tests for {@link WebFluxManagementChildContextConfiguration}.
*
* @author Moritz Halbritter
*/
class ReactiveManagementChildContextConfigurationTests {
class WebFluxManagementChildContextConfigurationTests {
@Test
// gh-45857
void failsWithoutManagementServerPropertiesBeanFromParent() {
new ReactiveWebApplicationContextRunner()
.run((parent) -> new ReactiveWebApplicationContextRunner().withParent(parent)
.withUserConfiguration(ReactiveManagementChildContextConfiguration.class)
.withUserConfiguration(WebFluxManagementChildContextConfiguration.class)
.run((context) -> assertThat(context).hasFailed()));
}
@@ -44,7 +44,7 @@ class ReactiveManagementChildContextConfigurationTests {
void succeedsWithManagementServerPropertiesBeanFromParent() {
new ReactiveWebApplicationContextRunner().withBean(ManagementServerProperties.class)
.run((parent) -> new ReactiveWebApplicationContextRunner().withParent(parent)
.withUserConfiguration(ReactiveManagementChildContextConfiguration.class)
.withUserConfiguration(WebFluxManagementChildContextConfiguration.class)
.run((context) -> assertThat(context).hasNotFailed()));
}

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,14 +14,14 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.endpoint.web;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.AbstractWebFluxEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.AbstractWebFluxEndpointHandlerMappingRuntimeHints;
import static org.assertj.core.api.Assertions.assertThat;
@@ -39,11 +39,11 @@ class AbstractWebFluxEndpointHandlerMappingTests {
getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection()
.onType(TypeReference
.of("org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.WriteOperationHandler")))
.of("org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.WriteOperationHandler")))
.accepts(runtimeHints);
assertThat(RuntimeHintsPredicates.reflection()
.onType(TypeReference
.of("org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping.ReadOperationHandler")))
.of("org.springframework.boot.webflux.actuate.endpoint.web.AbstractWebFluxEndpointHandlerMapping.ReadOperationHandler")))
.accepts(runtimeHints);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2024 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.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.endpoint.web;
import java.time.Duration;
import java.util.Arrays;

View File

@@ -14,15 +14,15 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.reactive;
package org.springframework.boot.webflux.actuate.endpoint.web;
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping.WebFluxEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping.WebFluxLinksHandler;
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping.WebFluxEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping.WebFluxLinksHandler;
import static org.assertj.core.api.Assertions.assertThat;

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.reactive;
package org.springframework.boot.webflux.actuate.web.exchanges;
import java.util.EnumSet;

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.reactive;
package org.springframework.boot.webflux.actuate.web.exchanges;
import java.security.Principal;
import java.time.Duration;

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.reactive;
package org.springframework.boot.webflux.actuate.web.exchanges;
import java.net.InetSocketAddress;
import java.net.URI;

View File

@@ -23,10 +23,10 @@ import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.reactor.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.webflux.actuate.endpoint.web.WebFluxEndpointHandlerMapping;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;