From 681fdb1ee80670cec20867f9540627ee1bdc6103 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 13 Dec 2017 17:47:18 +0100 Subject: [PATCH] Property detect Health web extension with management context Previously, the Health web extension was defined in the management context and, as a result, it wasn't found when a separate port was required. The side effect is that anything that the health web extension does was not active anymore in that case. This commit makes sure that the extension is always defined as part of the main context where operations are discovered and merged. Closes gh-11285 --- .../HealthEndpointAutoConfiguration.java | 19 ++++----- .../health/HealthEndpointConfiguration.java | 42 +++++++++++++++++++ ...lthEndpointWebExtensionConfiguration.java} | 8 ++-- .../main/resources/META-INF/spring.factories | 1 - ...FoundryActuatorAutoConfigurationTests.java | 2 - ...FoundryActuatorAutoConfigurationTests.java | 2 - ...a => HealthEndpointWebExtensionTests.java} | 13 +++--- ...ctiveHealthEndpointWebExtensionTests.java} | 8 ++-- .../actuator/ExampleHealthIndicator.java | 31 ++++++++++++++ ...AndPathSampleActuatorApplicationTests.java | 2 +- ...entPortSampleActuatorApplicationTests.java | 4 +- 11 files changed, 97 insertions(+), 35 deletions(-) create mode 100644 spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java rename spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/{HealthWebEndpointManagementContextConfiguration.java => HealthEndpointWebExtensionConfiguration.java} (94%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/{HealthWebEndpointServletManagementContextConfigurationTests.java => HealthEndpointWebExtensionTests.java} (85%) rename spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/{HealthWebEndpointReactiveManagementContextConfigurationTests.java => ReactiveHealthEndpointWebExtensionTests.java} (93%) create mode 100644 spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleHealthIndicator.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfiguration.java index eb06dd9773..5a387f3c4f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointAutoConfiguration.java @@ -16,14 +16,12 @@ package org.springframework.boot.actuate.autoconfigure.health; -import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; import org.springframework.boot.actuate.health.HealthEndpoint; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link HealthEndpoint}. @@ -34,14 +32,11 @@ import org.springframework.context.annotation.Configuration; * @since 2.0.0 */ @Configuration -@EnableConfigurationProperties(HealthEndpointProperties.class) +@EnableConfigurationProperties({ HealthEndpointProperties.class, + HealthIndicatorProperties.class }) +@AutoConfigureAfter(HealthIndicatorAutoConfiguration.class) +@Import({ HealthEndpointConfiguration.class, + HealthEndpointWebExtensionConfiguration.class }) public class HealthEndpointAutoConfiguration { - @Bean - @ConditionalOnMissingBean - @ConditionalOnEnabledEndpoint - public HealthEndpoint healthEndpoint(ApplicationContext applicationContext) { - return new HealthEndpoint(HealthIndicatorBeansComposite.get(applicationContext)); - } - } diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java new file mode 100644 index 0000000000..27c9ef2035 --- /dev/null +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointConfiguration.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2017 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 + * + * http://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.health; + +import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; +import org.springframework.boot.actuate.health.HealthEndpoint; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Configuration for {@link HealthEndpoint}. + * + * @author Stephane Nicoll + */ +@Configuration +class HealthEndpointConfiguration { + + @Bean + @ConditionalOnMissingBean + @ConditionalOnEnabledEndpoint + public HealthEndpoint healthEndpoint(ApplicationContext applicationContext) { + return new HealthEndpoint(HealthIndicatorBeansComposite.get( + applicationContext)); + } + +} diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointManagementContextConfiguration.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java similarity index 94% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointManagementContextConfiguration.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java index 20b6dba5fe..fbf3bbcbee 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointManagementContextConfiguration.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionConfiguration.java @@ -21,7 +21,6 @@ import java.util.Map; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint; -import org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration; import org.springframework.boot.actuate.health.CompositeReactiveHealthIndicatorFactory; import org.springframework.boot.actuate.health.HealthAggregator; import org.springframework.boot.actuate.health.HealthEndpoint; @@ -41,14 +40,13 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** - * {@link ManagementContextConfiguration} for health endpoints. + * Configuration for health endpoint web extensions. * * @author Stephane Nicoll - * @since 2.0.0 */ -@ManagementContextConfiguration +@Configuration @EnableConfigurationProperties(HealthIndicatorProperties.class) -public class HealthWebEndpointManagementContextConfiguration { +class HealthEndpointWebExtensionConfiguration { @Bean @ConditionalOnMissingBean diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories index 213bba4b49..8b1df5fca6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories @@ -50,7 +50,6 @@ org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguratio org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.endpoint.web.jersey.JerseyWebEndpointManagementContextConfiguration,\ -org.springframework.boot.actuate.autoconfigure.health.HealthWebEndpointManagementContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.jolokia.JolokiaManagementContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.web.jersey.JerseyManagementChildContextConfiguration,\ org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementChildContextConfiguration,\ diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java index d3cc6613ed..4835fc71d4 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java @@ -29,7 +29,6 @@ import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryH import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.health.HealthWebEndpointManagementContextConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.endpoint.EndpointInfo; import org.springframework.boot.actuate.endpoint.annotation.Endpoint; @@ -228,7 +227,6 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests { public void healthEndpointInvokerShouldBeCloudFoundryWebExtension() { setupContextWithCloudEnabled(); this.context.register(HealthEndpointAutoConfiguration.class, - HealthWebEndpointManagementContextConfiguration.class, CloudFoundryHealthWebEndpointManagementContextConfiguration.class); this.context.refresh(); Collection> endpoints = getHandlerMapping() diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java index 9ef59344cf..c97b2219cd 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfigurationTests.java @@ -28,7 +28,6 @@ import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryH import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.health.HealthEndpointAutoConfiguration; -import org.springframework.boot.actuate.autoconfigure.health.HealthWebEndpointManagementContextConfiguration; import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; import org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration; import org.springframework.boot.actuate.endpoint.EndpointInfo; @@ -250,7 +249,6 @@ public class CloudFoundryActuatorAutoConfigurationTests { "vcap.application.cf_api:http://my-cloud-controller.com") .applyTo(this.context); this.context.register(HealthEndpointAutoConfiguration.class, - HealthWebEndpointManagementContextConfiguration.class, CloudFoundryHealthWebEndpointManagementContextConfiguration.class); this.context.refresh(); Collection> endpoints = this.context diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointServletManagementContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java similarity index 85% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointServletManagementContextConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java index 42952aff02..8c3901d1d6 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointServletManagementContextConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthEndpointWebExtensionTests.java @@ -20,27 +20,28 @@ import java.util.Map; import org.junit.Test; +import org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration; import org.springframework.boot.actuate.health.HealthEndpointWebExtension; import org.springframework.boot.actuate.health.HealthStatusHttpMapper; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link HealthWebEndpointManagementContextConfiguration} in a servlet - * environment. + * Tests for {@link EndpointAutoConfiguration} in a servlet environment. * * @author Andy Wilkinson * @author Stephane Nicoll * @author Phillip Webb */ -public class HealthWebEndpointServletManagementContextConfigurationTests { +public class HealthEndpointWebExtensionTests { private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() - .withUserConfiguration(HealthIndicatorAutoConfiguration.class, - HealthEndpointAutoConfiguration.class, - HealthWebEndpointManagementContextConfiguration.class); + .withConfiguration(AutoConfigurations.of( + HealthIndicatorAutoConfiguration.class, + HealthEndpointAutoConfiguration.class)); @Test public void runShouldCreateExtensionBeans() { diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointReactiveManagementContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java similarity index 93% rename from spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointReactiveManagementContextConfigurationTests.java rename to spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java index 90d509f4f3..c2cdec724a 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/HealthWebEndpointReactiveManagementContextConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/health/ReactiveHealthEndpointWebExtensionTests.java @@ -35,19 +35,17 @@ import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link HealthWebEndpointManagementContextConfiguration} in a reactive - * environment. + * Tests for {@link HealthEndpointAutoConfiguration} in a reactive environment. * * @author Andy Wilkinson * @author Stephane Nicoll * @author Phillip Webb */ -public class HealthWebEndpointReactiveManagementContextConfigurationTests { +public class ReactiveHealthEndpointWebExtensionTests { private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() .withUserConfiguration(HealthIndicatorAutoConfiguration.class, - HealthEndpointAutoConfiguration.class, - HealthWebEndpointManagementContextConfiguration.class); + HealthEndpointAutoConfiguration.class); @Test public void runShouldCreateExtensionBeans() { diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleHealthIndicator.java b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleHealthIndicator.java new file mode 100644 index 0000000000..e27a7741de --- /dev/null +++ b/spring-boot-samples/spring-boot-sample-actuator/src/main/java/sample/actuator/ExampleHealthIndicator.java @@ -0,0 +1,31 @@ +/* + * Copyright 2012-2017 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 + * + * http://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 sample.actuator; + +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.HealthIndicator; +import org.springframework.stereotype.Component; + +@Component +public class ExampleHealthIndicator implements HealthIndicator { + + @Override + public Health health() { + return Health.up().withDetail("counter", 42).build(); + } + +} diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortAndPathSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortAndPathSampleActuatorApplicationTests.java index c5489fa0c8..65fb4ca49b 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortAndPathSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortAndPathSampleActuatorApplicationTests.java @@ -75,7 +75,7 @@ public class ManagementPortAndPathSampleActuatorApplicationTests { .getForEntity("http://localhost:" + this.managementPort + "/admin/health", String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(entity.getBody()).contains("\"status\":\"UP\""); + assertThat(entity.getBody()).isEqualTo("{\"status\":\"UP\"}"); } @Test diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortSampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortSampleActuatorApplicationTests.java index c7329e0784..1ea4cdf2e7 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortSampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/ManagementPortSampleActuatorApplicationTests.java @@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { - "management.server.port=0" }) + "management.server.port=0", "management.endpoint.health.show-details=true" }) public class ManagementPortSampleActuatorApplicationTests { @LocalServerPort @@ -77,6 +77,8 @@ public class ManagementPortSampleActuatorApplicationTests { String.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(entity.getBody()).contains("\"status\":\"UP\""); + assertThat(entity.getBody()).contains("\"example\""); + assertThat(entity.getBody()).contains("\"counter\":42"); } @Test