Move Actuator infrastructure for WebMvc to spring-boot-webmvc

Issue: 46121
This commit is contained in:
Stéphane Nicoll 2025-05-29 19:17:12 +02:00 committed by Phillip Webb
parent 791fd90359
commit 4dae86a8fc
52 changed files with 386 additions and 290 deletions

View File

@ -43,7 +43,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.servlet.AbstractWebMvcEndpointHandlerMapping;
import org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

View File

@ -1,185 +0,0 @@
/*
* Copyright 2012-present 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.endpoint.web.servlet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.EndpointAccessResolver;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
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.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.endpoint.web.servlet.AdditionalHealthEndpointPathsWebMvcHandlerMapping;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
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.context.annotation.Bean;
import org.springframework.context.annotation.Role;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* {@link ManagementContextConfiguration @ManagementContextConfiguration} for Spring MVC
* {@link Endpoint @Endpoint} concerns.
*
* @author Andy Wilkinson
* @author Phillip Webb
* @since 2.0.0
*/
@ManagementContextConfiguration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@ConditionalOnBean({ DispatcherServlet.class, WebEndpointsSupplier.class })
@EnableConfigurationProperties(CorsEndpointProperties.class)
public class WebMvcEndpointManagementContextConfiguration {
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("removal")
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,
org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier controllerEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties, Environment environment) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
String basePath = webEndpointProperties.getBasePath();
EndpointMapping endpointMapping = new EndpointMapping(basePath);
boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
shouldRegisterLinksMapping);
}
private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,
String basePath) {
return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)
|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
}
@Bean
@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)
@ConditionalOnBean(HealthEndpoint.class)
@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)
public AdditionalHealthEndpointPathsWebMvcHandlerMapping managementHealthEndpointWebMvcHandlerMapping(
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
ExposableWebEndpoint healthEndpoint = webEndpoints.stream()
.filter(this::isHealthEndpoint)
.findFirst()
.orElse(null);
return new AdditionalHealthEndpointPathsWebMvcHandlerMapping(healthEndpoint,
groups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT));
}
private boolean isHealthEndpoint(ExposableWebEndpoint endpoint) {
return endpoint.getEndpointId().equals(HealthEndpoint.ID);
}
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("removal")
@Deprecated(since = "3.3.5", forRemoval = true)
public org.springframework.boot.actuate.endpoint.web.servlet.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.servlet.ControllerEndpointHandlerMapping(
endpointMapping, controllerEndpointsSupplier.getEndpoints(), corsProperties.toCorsConfiguration(),
endpointAccessResolver);
}
@Bean
@ConditionalOnBean(EndpointObjectMapper.class)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static EndpointObjectMapperWebMvcConfigurer endpointObjectMapperWebMvcConfigurer(
EndpointObjectMapper endpointObjectMapper) {
return new EndpointObjectMapperWebMvcConfigurer(endpointObjectMapper);
}
/**
* {@link WebMvcConfigurer} to apply {@link EndpointObjectMapper} for
* {@link OperationResponseBody} to
* {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter}
* instances.
*/
@SuppressWarnings("removal")
static class EndpointObjectMapperWebMvcConfigurer implements WebMvcConfigurer {
private static final List<MediaType> MEDIA_TYPES = Collections
.unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType("application", "*+json")));
private final EndpointObjectMapper endpointObjectMapper;
EndpointObjectMapperWebMvcConfigurer(EndpointObjectMapper endpointObjectMapper) {
this.endpointObjectMapper = endpointObjectMapper;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof org.springframework.http.converter.json.MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter) {
configure(mappingJackson2HttpMessageConverter);
}
}
}
@SuppressWarnings({ "removal", "deprecation" })
private void configure(org.springframework.http.converter.json.MappingJackson2HttpMessageConverter converter) {
converter.registerObjectMappersForType(OperationResponseBody.class, (associations) -> {
ObjectMapper objectMapper = this.endpointObjectMapper.get();
MEDIA_TYPES.forEach((mimeType) -> associations.put(mimeType, objectMapper));
});
}
}
}

View File

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

View File

@ -36,4 +36,3 @@ org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinTracingAutoC
org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.exchanges.HttpExchangesEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.mappings.MappingsEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration

View File

@ -22,7 +22,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.servlet.WebMvcEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@ -30,6 +29,7 @@ import org.springframework.boot.http.converter.autoconfigure.HttpMessageConverte
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.webmvc.actuate.autoconfigure.endpoint.web.WebMvcEndpointManagementContextConfiguration;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.http.HttpHeaders;

View File

@ -28,7 +28,6 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfi
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.data.rest.autoconfigure.RepositoryRestMvcAutoConfiguration;
@ -38,6 +37,7 @@ import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.security.autoconfigure.servlet.SecurityAutoConfiguration;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.web.context.servlet.AnnotationConfigServletWebApplicationContext;
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.context.annotation.Bean;

View File

@ -31,6 +31,7 @@ import org.springframework.boot.tomcat.actuate.autoconfigure.web.TomcatServletMa
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.web.server.context.ServerPortInfoApplicationContextInitializer;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.webmvc.actuate.autoconfigure.health.WebMvcHealthEndpointExtensionAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.web.context.ConfigurableWebApplicationContext;
@ -51,7 +52,8 @@ class WebMvcHealthEndpointAdditionalPathIntegrationTests extends
TomcatServletManagementContextAutoConfiguration.class, WebMvcAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class, WebEndpointAutoConfiguration.class,
EndpointAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
HealthEndpointAutoConfiguration.class, DiskSpaceHealthContributorAutoConfiguration.class))
HealthEndpointAutoConfiguration.class, WebMvcHealthEndpointExtensionAutoConfiguration.class,
DiskSpaceHealthContributorAutoConfiguration.class))
.withInitializer(new ServerPortInfoApplicationContextInitializer())
.withPropertyValues("server.port=0"));
}

View File

@ -122,14 +122,14 @@ class MvcEndpointRequestIntegrationTests extends AbstractEndpointRequestIntegrat
@Override
protected WebApplicationContextRunner createContextRunner() {
return new WebApplicationContextRunner(AnnotationConfigServletWebServerApplicationContext::new)
.withUserConfiguration(WebMvcEndpointConfiguration.class)
.withUserConfiguration(InfrastructureTestConfiguration.class)
.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,
HttpMessageConvertersAutoConfiguration.class, WebMvcAutoConfiguration.class));
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(WebEndpointProperties.class)
static class WebMvcEndpointConfiguration {
static class InfrastructureTestConfiguration {
@Bean
TomcatServletWebServerFactory tomcat() {

View File

@ -20,7 +20,6 @@ import org.junit.jupiter.api.Test;
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.servlet.WebMvcEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider;
import org.springframework.boot.actuate.web.mappings.MappingsEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@ -28,6 +27,7 @@ import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoCon
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.webmvc.actuate.autoconfigure.endpoint.web.WebMvcEndpointManagementContextConfiguration;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;

View File

@ -35,14 +35,12 @@ dependencies {
optional("io.micrometer:micrometer-core")
optional("io.projectreactor:reactor-core")
optional("jakarta.servlet:jakarta.servlet-api")
optional("org.springframework:spring-webmvc")
optional("org.springframework.security:spring-security-config")
testFixturesImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation("org.springframework:spring-web")
testImplementation("org.springframework:spring-webflux")
testRuntimeOnly("ch.qos.logback:logback-classic")

View File

@ -16,14 +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.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
import org.springframework.boot.actuate.endpoint.web.servlet.AdditionalHealthEndpointPathsWebMvcHandlerMapping;
import org.springframework.boot.actuate.health.HealthContributorRegistry;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.boot.actuate.health.HealthEndpointGroups;
@ -34,7 +28,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
/**
* Configuration for {@link HealthEndpoint} web extensions.
@ -57,25 +50,4 @@ class HealthEndpointWebExtensionConfiguration {
properties.getLogging().getSlowIndicatorThreshold());
}
private static ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
return webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
.findFirst()
.orElse(null);
}
@ConditionalOnBean(DispatcherServlet.class)
static class MvcAdditionalHealthEndpointPathsConfiguration {
@Bean
AdditionalHealthEndpointPathsWebMvcHandlerMapping healthEndpointWebMvcHandlerMapping(
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
ExposableWebEndpoint health = getHealthEndpoint(webEndpointsSupplier);
return new AdditionalHealthEndpointPathsWebMvcHandlerMapping(health,
groups.getAllWithAdditionalPath(WebServerNamespace.SERVER));
}
}
}

View File

@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProp
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.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.filter.ApplicationContextHeaderFilter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@ -40,6 +41,7 @@ import org.springframework.context.annotation.Configuration;
@AutoConfiguration
@ConditionalOnClass(Servlet.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(WebEndpointProperties.class)
public class ServletManagementContextAutoConfiguration {
@Bean

View File

@ -1 +1,2 @@
org.springframework.boot.actuate.autoconfigure.endpoint.web.ServletEndpointManagementContextConfiguration
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementChildContextConfiguration

View File

@ -7,3 +7,4 @@ org.springframework.boot.actuate.autoconfigure.info.InfoEndpointAutoConfiguratio
org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.logging.LoggersEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration

View File

@ -28,7 +28,6 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.condition.WithTes
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.autoconfigure.health.HealthEndpointWebExtensionConfiguration.MvcAdditionalHealthEndpointPathsConfiguration;
import org.springframework.boot.actuate.endpoint.ApiVersion;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;
@ -60,7 +59,6 @@ import org.springframework.boot.test.context.runner.ReactiveWebApplicationContex
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -342,24 +340,6 @@ class HealthEndpointAutoConfigurationTests {
}));
}
@Test
@WithTestEndpointOutcomeExposureContributor
void additionalHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {
this.contextRunner
.withConfiguration(
AutoConfigurations.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))
.withBean(DispatcherServlet.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(HealthEndpointWebExtension.class);
assertThat(context.getBean(WebEndpointsSupplier.class).getEndpoints()).isEmpty();
assertThat(context).hasSingleBean(MvcAdditionalHealthEndpointPathsConfiguration.class);
});
}
@Test
@WithTestEndpointOutcomeExposureContributor
void additionalReactiveHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {

View File

@ -32,7 +32,6 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfi
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.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration;
import org.springframework.boot.actuate.docs.AbstractEndpointDocumentationTests.BaseDocumentationConfiguration;
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
@ -41,6 +40,7 @@ import org.springframework.boot.http.converter.autoconfigure.HttpMessageConverte
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.webflux.autoconfigure.HttpHandlerAutoConfiguration;
import org.springframework.boot.webflux.autoconfigure.WebFluxAutoConfiguration;
import org.springframework.boot.webmvc.actuate.autoconfigure.endpoint.web.WebMvcEndpointManagementContextConfiguration;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.context.annotation.Bean;

View File

@ -38,6 +38,7 @@ import org.springframework.boot.test.context.runner.ContextConsumer;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.webmvc.actuate.endpoint.web.ControllerEndpointHandlerMapping;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

View File

@ -37,6 +37,7 @@ import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.tomcat.autoconfigure.servlet.TomcatServletWebServerAutoConfiguration;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.error.ErrorMvcAutoConfiguration;

View File

@ -44,9 +44,8 @@ dependencies {
optional("io.micrometer:micrometer-registry-prometheus-simpleclient")
optional("io.prometheus:prometheus-metrics-exposition-formats")
optional("io.prometheus:prometheus-metrics-exporter-pushgateway")
optional("io.undertow:undertow-servlet")
optional("jakarta.servlet:jakarta.servlet-api")
optional("javax.cache:cache-api")
optional("org.apache.tomcat.embed:tomcat-embed-core")
optional("org.aspectj:aspectjweaver")
optional("org.eclipse.angus:angus-mail")
optional("org.hibernate.validator:hibernate-validator")
@ -55,8 +54,6 @@ dependencies {
optional("org.springframework:spring-jdbc")
optional("org.springframework:spring-messaging")
optional("org.springframework:spring-webflux")
optional("org.springframework:spring-web")
optional("org.springframework:spring-webmvc")
optional("org.springframework.graphql:spring-graphql")
optional("org.springframework.data:spring-data-rest-webmvc")
optional("org.springframework.security:spring-security-core")
@ -71,7 +68,6 @@ dependencies {
testImplementation(project(":spring-boot-project:spring-boot-jsonb"))
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation("com.squareup.okhttp3:mockwebserver")
testImplementation("io.micrometer:micrometer-observation-test")
testImplementation("io.projectreactor:reactor-test")
testImplementation("net.minidev:json-smart")

View File

@ -41,6 +41,8 @@ dependencies {
optional(project(":spring-boot-project:spring-boot-undertow"))
optional(project(":spring-boot-project:spring-boot-validation"))
optional(project(":spring-boot-project:spring-boot-web-server"))
optional("com.fasterxml.jackson.core:jackson-databind")
optional("io.projectreactor:reactor-core")
testFixturesApi(testFixtures(project(":spring-boot-project:spring-boot-actuator")))
testFixturesImplementation(project(":spring-boot-project:spring-boot-http-converter"))
@ -52,6 +54,7 @@ dependencies {
testImplementation(project(":spring-boot-project:spring-boot-tomcat"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(project(":spring-boot-project:spring-boot-web-server-test"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-actuator-autoconfigure")))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-web-server")))
testImplementation("jakarta.servlet:jakarta.servlet-api")
testImplementation("org.aspectj:aspectjweaver")

View File

@ -16,23 +16,129 @@
package org.springframework.boot.webmvc.actuate.autoconfigure.endpoint.web;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
import org.springframework.boot.actuate.autoconfigure.endpoint.expose.EndpointExposure;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.EndpointAccessResolver;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.OperationResponseBody;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
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.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.condition.ConditionalOnBean;
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.webmvc.actuate.endpoint.web.AdditionalHealthEndpointPathsWebMvcHandlerMapping;
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Role;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* {@link ManagementContextConfiguration @ManagementContextConfiguration} for Spring MVC
* {@link Endpoint @Endpoint} concerns.
*
* @author Andy Wilkinson
* @author Phillip Webb
* @author Stephane Nicoll
* @since 4.0.0
*/
@ManagementContextConfiguration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
class WebMvcEndpointManagementContextConfiguration {
@ConditionalOnBean({ DispatcherServlet.class, WebEndpointsSupplier.class })
@EnableConfigurationProperties(CorsEndpointProperties.class)
public class WebMvcEndpointManagementContextConfiguration {
@Bean
@SuppressWarnings({ "deprecation", "removal" })
@ConditionalOnMissingBean
@SuppressWarnings("removal")
WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier,
org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,
org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier controllerEndpointsSupplier,
EndpointMediaTypes endpointMediaTypes, CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties, Environment environment) {
List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
allEndpoints.addAll(webEndpoints);
allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());
allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());
String basePath = webEndpointProperties.getBasePath();
EndpointMapping endpointMapping = new EndpointMapping(basePath);
boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(webEndpointProperties, environment, basePath);
return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes,
corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath),
shouldRegisterLinksMapping);
}
private boolean shouldRegisterLinksMapping(WebEndpointProperties webEndpointProperties, Environment environment,
String basePath) {
return webEndpointProperties.getDiscovery().isEnabled() && (StringUtils.hasText(basePath)
|| ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));
}
@Bean
@ConditionalOnManagementPort(ManagementPortType.DIFFERENT)
@ConditionalOnBean(HealthEndpoint.class)
@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)
AdditionalHealthEndpointPathsWebMvcHandlerMapping managementHealthEndpointWebMvcHandlerMapping(
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
ExposableWebEndpoint healthEndpoint = webEndpoints.stream()
.filter(this::isHealthEndpoint)
.findFirst()
.orElse(null);
return new AdditionalHealthEndpointPathsWebMvcHandlerMapping(healthEndpoint,
groups.getAllWithAdditionalPath(WebServerNamespace.MANAGEMENT));
}
private boolean isHealthEndpoint(ExposableWebEndpoint endpoint) {
return endpoint.getEndpointId().equals(HealthEndpoint.ID);
}
@Bean
@ConditionalOnMissingBean
@SuppressWarnings("removal")
@Deprecated(since = "3.3.5", forRemoval = true)
org.springframework.boot.webmvc.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.webmvc.actuate.endpoint.web.ControllerEndpointHandlerMapping(
endpointMapping, controllerEndpointsSupplier.getEndpoints(), corsProperties.toCorsConfiguration(),
endpointAccessResolver);
}
@Bean
@SuppressWarnings("removal")
org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar servletEndpointRegistrar(
WebEndpointProperties properties,
org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier servletEndpointsSupplier,
@ -42,4 +148,49 @@ class WebMvcEndpointManagementContextConfiguration {
servletEndpointsSupplier.getEndpoints(), endpointAccessResolver);
}
@Bean
@ConditionalOnBean(EndpointObjectMapper.class)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
static EndpointObjectMapperWebMvcConfigurer endpointObjectMapperWebMvcConfigurer(
EndpointObjectMapper endpointObjectMapper) {
return new EndpointObjectMapperWebMvcConfigurer(endpointObjectMapper);
}
/**
* {@link WebMvcConfigurer} to apply {@link EndpointObjectMapper} for
* {@link OperationResponseBody} to
* {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter}
* instances.
*/
@SuppressWarnings("removal")
static class EndpointObjectMapperWebMvcConfigurer implements WebMvcConfigurer {
private static final List<MediaType> MEDIA_TYPES = Collections
.unmodifiableList(Arrays.asList(MediaType.APPLICATION_JSON, new MediaType("application", "*+json")));
private final EndpointObjectMapper endpointObjectMapper;
EndpointObjectMapperWebMvcConfigurer(EndpointObjectMapper endpointObjectMapper) {
this.endpointObjectMapper = endpointObjectMapper;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof org.springframework.http.converter.json.MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter) {
configure(mappingJackson2HttpMessageConverter);
}
}
}
@SuppressWarnings("removal")
private void configure(org.springframework.http.converter.json.MappingJackson2HttpMessageConverter converter) {
converter.registerObjectMappersForType(OperationResponseBody.class, (associations) -> {
ObjectMapper objectMapper = this.endpointObjectMapper.get();
MEDIA_TYPES.forEach((mimeType) -> associations.put(mimeType, objectMapper));
});
}
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2012-present 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.webmvc.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.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.ConditionalOnBean;
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.webmvc.actuate.endpoint.web.AdditionalHealthEndpointPathsWebMvcHandlerMapping;
import org.springframework.context.annotation.Bean;
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link HealthEndpoint} web
* extension with Spring MVC.
*
* @author Stephane Nicoll
* @since 4.0.0
*/
@AutoConfiguration
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(HealthEndpoint.class)
@ConditionalOnBean(HealthEndpoint.class)
@ConditionalOnAvailableEndpoint(endpoint = HealthEndpoint.class, exposure = EndpointExposure.WEB)
public class WebMvcHealthEndpointExtensionAutoConfiguration {
@Bean
public AdditionalHealthEndpointPathsWebMvcHandlerMapping healthEndpointWebMvcHandlerMapping(
WebEndpointsSupplier webEndpointsSupplier, HealthEndpointGroups groups) {
ExposableWebEndpoint health = getHealthEndpoint(webEndpointsSupplier);
return new AdditionalHealthEndpointPathsWebMvcHandlerMapping(health,
groups.getAllWithAdditionalPath(WebServerNamespace.SERVER));
}
private static ExposableWebEndpoint getHealthEndpoint(WebEndpointsSupplier webEndpointsSupplier) {
Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();
return webEndpoints.stream()
.filter((endpoint) -> endpoint.getEndpointId().equals(HealthEndpoint.ID))
.findFirst()
.orElse(null);
}
}

View File

@ -15,6 +15,6 @@
*/
/**
* Auto-configuration for exposing actuator web endpoints using Spring MVC.
* Auto-configuration for actuator health concerns.
*/
package org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.health;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.web;
import java.util.ArrayList;
import java.util.List;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.web;
import java.util.ArrayList;
import java.util.List;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.web;
import java.util.ArrayList;
import java.util.List;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.web;
import java.util.Map;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.web;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration;

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012-present 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.
*/
/**
* Actuator Spring MVC support.
*/
package org.springframework.boot.webmvc.actuate.autoconfigure.web;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.servlet;
package org.springframework.boot.webmvc.actuate.endpoint.web;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
@ -50,8 +50,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.servlet.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.web.server.context.WebServerApplicationContext;
import org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.servlet;
package org.springframework.boot.webmvc.actuate.endpoint.web;
import java.util.Collection;
import java.util.Collections;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.servlet;
package org.springframework.boot.webmvc.actuate.endpoint.web;
import java.lang.reflect.Method;
import java.util.Collection;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.servlet;
package org.springframework.boot.webmvc.actuate.endpoint.web;
import java.util.Collection;
import java.util.Collections;
@ -34,7 +34,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.servlet.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.cors.CorsConfiguration;

View File

@ -17,4 +17,4 @@
/**
* Spring MVC support for actuator endpoints.
*/
package org.springframework.boot.actuate.endpoint.web.servlet;
package org.springframework.boot.webmvc.actuate.endpoint.web;

View File

@ -1 +1,2 @@
org.springframework.boot.webmvc.actuate.autoconfigure.endpoint.web.WebMvcEndpointManagementContextConfiguration
org.springframework.boot.webmvc.actuate.autoconfigure.web.WebMvcEndpointChildContextConfiguration

View File

@ -1,3 +1,4 @@
org.springframework.boot.webmvc.actuate.autoconfigure.health.WebMvcHealthEndpointExtensionAutoConfiguration
org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration
org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration
org.springframework.boot.webmvc.autoconfigure.error.ErrorMvcAutoConfiguration

View File

@ -20,18 +20,20 @@ import java.util.Collections;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.endpoint.Access;
import org.springframework.boot.actuate.endpoint.EndpointAccessResolver;
import org.springframework.boot.actuate.endpoint.web.ServletEndpointRegistrar;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletPath;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import static org.assertj.core.api.Assertions.assertThat;
@ -45,7 +47,9 @@ import static org.assertj.core.api.Assertions.assertThat;
class WebMvcEndpointManagementContextConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withUserConfiguration(TestConfig.class);
.withUserConfiguration(TestConfig.class)
.withConfiguration(AutoConfigurations.of(DispatcherServletAutoConfiguration.class,
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class));
@Test
void contextShouldContainServletEndpointRegistrar() {
@ -63,8 +67,7 @@ class WebMvcEndpointManagementContextConfigurationTests {
}
@Configuration(proxyBeanMethods = false)
@Import(WebMvcEndpointManagementContextConfiguration.class)
@EnableConfigurationProperties(WebEndpointProperties.class)
@ImportAutoConfiguration(WebMvcEndpointManagementContextConfiguration.class)
static class TestConfig {
@Bean

View File

@ -0,0 +1,84 @@
/*
* Copyright 2012-present 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.webmvc.actuate.autoconfigure.health;
import org.junit.jupiter.api.Test;
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.HealthEndpointWebExtension;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.webmvc.actuate.endpoint.web.AdditionalHealthEndpointPathsWebMvcHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link WebMvcHealthEndpointExtensionAutoConfiguration}.
*
* @author Stephane Nicoll
*/
class WebMvcHealthEndpointExtensionAutoConfigurationTests {
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(HealthContributorAutoConfiguration.class,
HealthEndpointAutoConfiguration.class, WebMvcHealthEndpointExtensionAutoConfiguration.class));
@Test
@WithTestEndpointOutcomeExposureContributor
void additionalHealthEndpointsPathsTolerateHealthEndpointThatIsNotWebExposed() {
this.contextRunner
.withConfiguration(
AutoConfigurations.of(EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class))
.withBean(DispatcherServlet.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(HealthEndpointWebExtension.class);
assertThat(context.getBean(WebEndpointsSupplier.class).getEndpoints()).isEmpty();
assertThat(context).hasSingleBean(AdditionalHealthEndpointPathsWebMvcHandlerMapping.class);
});
}
@Configuration(proxyBeanMethods = false)
static class HealthIndicatorsConfiguration {
@Bean
HealthIndicator simpleHealthIndicator() {
return () -> Health.up().withDetail("counter", 42).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.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.web;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.web;
import java.util.Collections;
import java.util.Map;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.web;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@ -32,6 +32,7 @@ import org.junit.jupiter.api.io.TempDir;
import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.autoconfigure.AutoConfigurations;

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.web.servlet;
package org.springframework.boot.webmvc.actuate.autoconfigure.web;
import org.junit.jupiter.api.Test;

View File

@ -14,14 +14,14 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.servlet;
package org.springframework.boot.webmvc.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.servlet.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.AbstractWebMvcEndpointHandlerMappingRuntimeHints;
import static org.assertj.core.api.Assertions.assertThat;
@ -38,7 +38,7 @@ class AbstractWebMvcEndpointHandlerMappingTests {
new AbstractWebMvcEndpointHandlerMappingRuntimeHints().registerHints(runtimeHints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection()
.onType(TypeReference
.of("org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping.OperationHandler")))
.of("org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping.OperationHandler")))
.accepts(runtimeHints);
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.servlet;
package org.springframework.boot.webmvc.actuate.endpoint.web;
import java.util.Arrays;

View File

@ -14,15 +14,15 @@
* limitations under the License.
*/
package org.springframework.boot.actuate.endpoint.web.servlet;
package org.springframework.boot.webmvc.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.servlet.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.WebMvcLinksHandler;
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping.WebMvcEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping.WebMvcLinksHandler;
import static org.assertj.core.api.Assertions.assertThat;

View File

@ -23,11 +23,11 @@ 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.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.http.converter.autoconfigure.HttpMessageConvertersAutoConfiguration;
import org.springframework.boot.jackson.autoconfigure.JacksonAutoConfiguration;
import org.springframework.boot.tomcat.servlet.TomcatServletWebServerFactory;
import org.springframework.boot.webmvc.actuate.endpoint.web.WebMvcEndpointHandlerMapping;
import org.springframework.boot.webmvc.autoconfigure.DispatcherServletAutoConfiguration;
import org.springframework.boot.webmvc.autoconfigure.WebMvcAutoConfiguration;
import org.springframework.context.ApplicationContext;

View File

@ -29,7 +29,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.servlet.AbstractWebMvcEndpointHandlerMapping;
import org.springframework.boot.webmvc.actuate.endpoint.web.AbstractWebMvcEndpointHandlerMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.cors.CorsConfiguration;