Make /refresh POST only and extend to non-bootstrap properties
This commit is contained in:
@@ -45,6 +45,7 @@ import org.springframework.platform.context.properties.ConfigurationPropertiesRe
|
||||
import org.springframework.platform.context.restart.RestartEndpoint;
|
||||
import org.springframework.platform.context.restart.RestartMvcEndpoint;
|
||||
import org.springframework.platform.context.scope.refresh.RefreshScope;
|
||||
import org.springframework.platform.endpoint.GenericPostableMvcEndpoint;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(RefreshScope.class)
|
||||
@@ -88,21 +89,22 @@ public class RefreshAutoConfiguration {
|
||||
@ConditionalOnClass(IntegrationMBeanExporter.class)
|
||||
protected static class RefreshEndpointWithIntegration {
|
||||
|
||||
@Autowired
|
||||
@Autowired(required=false)
|
||||
private IntegrationMBeanExporter exporter;
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RestartEndpoint restartEndpoint() {
|
||||
RestartEndpoint endpoint = new RestartEndpoint();
|
||||
if (exporter!=null) {
|
||||
if (exporter != null) {
|
||||
endpoint.setIntegrationMBeanExporter(exporter);
|
||||
}
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnMissingClass(name="org.springframework.integration.monitor.IntegrationMBeanExporter")
|
||||
@ConditionalOnMissingClass(name = "org.springframework.integration.monitor.IntegrationMBeanExporter")
|
||||
protected static class RefreshEndpointWithoutIntegration {
|
||||
|
||||
@Bean
|
||||
@@ -131,13 +133,16 @@ public class RefreshAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RefreshEndpoint refreshEndpoint(
|
||||
ConfigurableApplicationContext context,
|
||||
ConfigServiceBootstrapConfiguration bootstrap) {
|
||||
RefreshEndpoint endpoint = new RefreshEndpoint(context, bootstrap);
|
||||
public RefreshEndpoint refreshEndpoint(ConfigurableApplicationContext context) {
|
||||
RefreshEndpoint endpoint = new RefreshEndpoint(context);
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MvcEndpoint refreshMvcEndpoint(RefreshEndpoint endpoint) {
|
||||
return new GenericPostableMvcEndpoint(endpoint);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -20,23 +20,25 @@ import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
|
||||
import org.springframework.boot.context.config.ConfigFileApplicationListener;
|
||||
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.jmx.export.annotation.ManagedOperation;
|
||||
import org.springframework.jmx.export.annotation.ManagedResource;
|
||||
import org.springframework.platform.bootstrap.config.ConfigServiceBootstrapConfiguration;
|
||||
import org.springframework.platform.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.context.support.StandardServletEnvironment;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -46,28 +48,51 @@ import org.springframework.util.ReflectionUtils;
|
||||
@ManagedResource
|
||||
public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> {
|
||||
|
||||
private Set<String> standardSources = new HashSet<String>(Arrays.asList(
|
||||
StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME,
|
||||
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
|
||||
StandardServletEnvironment.JNDI_PROPERTY_SOURCE_NAME,
|
||||
StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
|
||||
StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
|
||||
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
private ConfigServiceBootstrapConfiguration bootstrap = new ConfigServiceBootstrapConfiguration();
|
||||
|
||||
public RefreshEndpoint(ConfigurableApplicationContext context, ConfigServiceBootstrapConfiguration bootstrap) {
|
||||
public RefreshEndpoint(ConfigurableApplicationContext context) {
|
||||
super("refresh");
|
||||
this.context = context;
|
||||
this.bootstrap = bootstrap;
|
||||
}
|
||||
|
||||
|
||||
@ManagedOperation
|
||||
public synchronized String[] refresh() {
|
||||
Map<String, Object> before = extract(context.getEnvironment().getPropertySources());
|
||||
bootstrap.initialize(context);
|
||||
new ConfigFileApplicationListener().onApplicationEvent(new ApplicationEnvironmentPreparedEvent(null, null, context.getEnvironment()));
|
||||
addConfigFilesToEnvironment();
|
||||
Set<String> keys = changes(before,
|
||||
extract(context.getEnvironment().getPropertySources())).keySet();
|
||||
if (keys.isEmpty()) {
|
||||
return new String[0];
|
||||
}
|
||||
context.publishEvent(new EnvironmentChangeEvent(keys));
|
||||
return keys.toArray(new String[keys.size()]);
|
||||
return keys.toArray(new String[keys.size()]);
|
||||
}
|
||||
|
||||
private void addConfigFilesToEnvironment() {
|
||||
ConfigurableApplicationContext capture = new SpringApplicationBuilder(Empty.class).showBanner(
|
||||
false).web(false).environment(context.getEnvironment()).run();
|
||||
MutablePropertySources target = context.getEnvironment().getPropertySources();
|
||||
for (PropertySource<?> source : capture.getEnvironment().getPropertySources()) {
|
||||
String name = source.getName();
|
||||
if (!standardSources.contains(name)) {
|
||||
if (target.contains(name)) {
|
||||
target.replace(name, source);
|
||||
} else {
|
||||
if (target.contains("defaultProperties")) {
|
||||
target.addBefore("defaultProperties", source);
|
||||
} else {
|
||||
target.addLast(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,8 +130,11 @@ public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> {
|
||||
|
||||
private Map<String, Object> extract(MutablePropertySources propertySources) {
|
||||
Map<String, Object> result = new HashMap<String, Object>();
|
||||
PropertySource<?> parent = propertySources.get("bootstrap");
|
||||
extract(parent, result);
|
||||
for (PropertySource<?> parent : propertySources) {
|
||||
if (!standardSources.contains(parent.getName())) {
|
||||
extract(parent, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -131,4 +159,9 @@ public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class Empty {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@ package org.springframework.platform.context.restart;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.platform.endpoint.GenericPostableMvcEndpoint;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@@ -66,25 +66,5 @@ public class RestartMvcEndpoint extends EndpointMvcAdapter {
|
||||
return new GenericPostableMvcEndpoint(((RestartEndpoint)getDelegate()).getResumeEndpoint());
|
||||
}
|
||||
|
||||
|
||||
private static class GenericPostableMvcEndpoint extends EndpointMvcAdapter {
|
||||
|
||||
public GenericPostableMvcEndpoint(Endpoint<?> delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
@Override
|
||||
public Object invoke() {
|
||||
if (!getDelegate().isEnabled()) {
|
||||
return new ResponseEntity<Map<String, String>>(Collections.singletonMap(
|
||||
"message", "This endpoint is disabled"), HttpStatus.NOT_FOUND);
|
||||
}
|
||||
return super.invoke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2013-2014 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.platform.endpoint;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
public class GenericPostableMvcEndpoint extends EndpointMvcAdapter {
|
||||
|
||||
public GenericPostableMvcEndpoint(Endpoint<?> delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
@Override
|
||||
public Object invoke() {
|
||||
if (!getDelegate().isEnabled()) {
|
||||
return new ResponseEntity<Map<String, String>>(Collections.singletonMap(
|
||||
"message", "This endpoint is disabled"), HttpStatus.NOT_FOUND);
|
||||
}
|
||||
return super.invoke();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -86,7 +86,7 @@ public class RefreshScopeConcurrencyTests {
|
||||
}
|
||||
}
|
||||
});
|
||||
assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
|
||||
assertTrue(latch.await(1500, TimeUnit.MILLISECONDS));
|
||||
logger.info("Refreshing");
|
||||
scope.refreshAll();
|
||||
assertEquals("Foo", service.getMessage());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
info:
|
||||
component: Config Sample
|
||||
component: Config Samples
|
||||
endpoints:
|
||||
restart:
|
||||
enabled: true
|
||||
Reference in New Issue
Block a user