Stop exposing a duplicate web extension for the env endpoint

An actuator endpoint is designed around a single class flagged with
`@Endpoint`. Such endpoint can have some of its operations refined with
a given tech (for instance via a `EndpointWebExtension` for web specific
concerns).

This design mandates that an endpoint (and its tech specific refinements
are managed centrally to form a unified contract).

As Spring Cloud is extending the standard Spring Boot's `env` endpoint,
this commit introduces a WritableEnvironmentEndpoint with a web
extension.

Closes gh-367
Closes gh-354
This commit is contained in:
Stephane Nicoll
2018-05-10 10:02:30 +02:00
committed by Dave Syer
parent 73e233dcd9
commit bf5de108e2
7 changed files with 110 additions and 37 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2014 the original author or authors.
* Copyright 2013-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,16 +15,10 @@
*/
package org.springframework.cloud.autoconfigure;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
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.web.servlet.WebMvcAutoConfiguration;
import org.springframework.cloud.context.environment.EnvironmentManager;
import org.springframework.cloud.context.environment.EnvironmentWebEndpointExtension;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
@@ -38,27 +32,13 @@ import org.springframework.core.env.ConfigurableEnvironment;
*
*/
@Configuration
@AutoConfigureAfter({ WebMvcAutoConfiguration.class,
RefreshEndpointAutoConfiguration.class })
@AutoConfigureAfter(WebMvcAutoConfiguration.class)
public class LifecycleMvcEndpointAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public EnvironmentManager environmentManager(ConfigurableEnvironment environment) {
return new EnvironmentManager(environment);
}
@Configuration
@ConditionalOnClass(EnvironmentEndpoint.class)
@ConditionalOnWebApplication
protected static class EndpointConfiguration {
@Bean
@ConditionalOnBean(EnvironmentEndpoint.class)
@ConditionalOnEnabledEndpoint
public EnvironmentWebEndpointExtension environmentWebEndpointExtension(
EnvironmentManager environment) {
return new EnvironmentWebEndpointExtension(environment);
}
}
@Bean
@ConditionalOnMissingBean
public EnvironmentManager environmentManager(ConfigurableEnvironment environment) {
return new EnvironmentManager(environment);
}
}

View File

@@ -46,7 +46,8 @@ import org.springframework.integration.monitor.IntegrationMBeanExporter;
*/
@Configuration
@ConditionalOnClass({EndpointAutoConfiguration.class, Health.class})
@AutoConfigureAfter({EndpointAutoConfiguration.class, RefreshAutoConfiguration.class})
@AutoConfigureAfter({ LifecycleMvcEndpointAutoConfiguration.class,
RefreshAutoConfiguration.class})
@Import({ RestartEndpointWithIntegrationConfiguration.class,
RestartEndpointWithoutIntegrationConfiguration.class,
PauseResumeEndpointsConfiguration.class })

View File

@@ -0,0 +1,62 @@
package org.springframework.cloud.autoconfigure;
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnEnabledEndpoint;
import org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointProperties;
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
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.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.environment.EnvironmentManager;
import org.springframework.cloud.context.environment.WritableEnvironmentEndpoint;
import org.springframework.cloud.context.environment.WritableEnvironmentEndpointWebExtension;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
/**
* {@link EnableAutoConfiguration Auto-configuration} for the
* {@link WritableEnvironmentEndpoint}.
*
* @author Stephane Nicoll
* @since 2.0.0
*/
@Configuration
@ConditionalOnClass({ EnvironmentEndpoint.class, EnvironmentEndpointProperties.class })
@ConditionalOnBean(EnvironmentManager.class)
@AutoConfigureBefore(EnvironmentEndpointAutoConfiguration.class)
@AutoConfigureAfter(LifecycleMvcEndpointAutoConfiguration.class)
@EnableConfigurationProperties({ EnvironmentEndpointProperties.class })
public class WritableEnvironmentEndpointAutoConfiguration {
private final EnvironmentEndpointProperties properties;
public WritableEnvironmentEndpointAutoConfiguration(
EnvironmentEndpointProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnEnabledEndpoint
public WritableEnvironmentEndpoint environmentEndpoint(Environment environment) {
WritableEnvironmentEndpoint endpoint = new WritableEnvironmentEndpoint(environment);
String[] keysToSanitize = this.properties.getKeysToSanitize();
if (keysToSanitize != null) {
endpoint.setKeysToSanitize(keysToSanitize);
}
return endpoint;
}
@Bean
@ConditionalOnEnabledEndpoint
public WritableEnvironmentEndpointWebExtension environmentWebEndpointExtension(
WritableEnvironmentEndpoint endpoint, EnvironmentManager environment) {
return new WritableEnvironmentEndpointWebExtension(endpoint, environment);
}
}

View File

@@ -0,0 +1,19 @@
package org.springframework.cloud.context.environment;
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
import org.springframework.core.env.Environment;
/**
* An extension of the standard {@link EnvironmentEndpoint} that allows to modify the
* environment at runtime.
*
* @author Stephane Nicoll
* @since 2.0.0
*/
public class WritableEnvironmentEndpoint extends EnvironmentEndpoint {
public WritableEnvironmentEndpoint(Environment environment) {
super(environment);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2014 the original author or authors.
* Copyright 2013-2018 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.
@@ -21,8 +21,7 @@ import java.util.Map;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;
import org.springframework.boot.actuate.env.EnvironmentEndpoint;
import org.springframework.boot.actuate.env.EnvironmentEndpointWebExtension;
/**
* MVC endpoint for the {@link EnvironmentManager} providing a POST to /env as a simple
@@ -31,13 +30,16 @@ import org.springframework.boot.actuate.env.EnvironmentEndpoint;
* @author Dave Syer
*
*/
@EndpointWebExtension(endpoint = EnvironmentEndpoint.class)
public class EnvironmentWebEndpointExtension {
@EndpointWebExtension(endpoint = WritableEnvironmentEndpoint.class)
public class WritableEnvironmentEndpointWebExtension
extends EnvironmentEndpointWebExtension {
private EnvironmentManager environment;
public EnvironmentWebEndpointExtension(EnvironmentManager enviroment) {
environment = enviroment;
public WritableEnvironmentEndpointWebExtension(WritableEnvironmentEndpoint endpoint,
EnvironmentManager environment) {
super(endpoint);
this.environment = environment;
}
@WriteOperation

View File

@@ -1,9 +1,10 @@
# AutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration,\
org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshAutoConfiguration,\
org.springframework.cloud.autoconfigure.RefreshEndpointAutoConfiguration,\
org.springframework.cloud.autoconfigure.LifecycleMvcEndpointAutoConfiguration
org.springframework.cloud.autoconfigure.WritableEnvironmentEndpointAutoConfiguration
# Application Listeners
org.springframework.context.ApplicationListener=\

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2006-2017 the original author or authors.
* Copyright 2006-2018 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.
@@ -18,6 +18,7 @@ package org.springframework.cloud.context.environment;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.ServletException;
@@ -44,6 +45,7 @@ import org.springframework.web.context.WebApplicationContext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -108,6 +110,12 @@ public class EnvironmentManagerIntegrationTests {
assertEquals(0, properties.getDelay());
}
@Test
public void coreWebExtensionAvailable() throws Exception {
this.mvc.perform(get(BASE_PATH + "/env/" + UUID.randomUUID().toString()))
.andExpect(status().isNotFound());
}
@Configuration
@EnableAutoConfiguration
protected static class TestConfiguration {