Isolate refresh/resume/pause/restart endpoints

This commit is contained in:
Dave Syer
2014-06-26 16:34:03 +01:00
parent fe8ff8fd8c
commit c3c2f0b43f
4 changed files with 138 additions and 6 deletions

View File

@@ -20,6 +20,7 @@ package org.springframework.platform.autoconfigure;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -28,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetaData;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -83,10 +85,22 @@ public class RefreshAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RestartEndpoint restartContextListener() {
public RestartEndpoint restartEndpoint() {
return new RestartEndpoint();
}
@Bean
@ConfigurationProperties("endpoints.pause")
public Endpoint<Boolean> pauseEndpoint(RestartEndpoint restartEndpoint) {
return restartEndpoint.getPauseEndpoint();
}
@Bean
@ConfigurationProperties("endpoints.resume")
public Endpoint<Boolean> resumeEndpoint(RestartEndpoint restartEndpoint) {
return restartEndpoint.getResumeEndpoint();
}
@Configuration
@ConditionalOnExpression("${endpoints.refresh.enabled:true}")
@ConditionalOnBean(ConfigServiceBootstrapConfiguration.class)
@@ -124,6 +138,16 @@ public class RefreshAutoConfiguration {
return new RestartMvcEndpoint(restartEndpoint);
}
@Bean
public MvcEndpoint pauseMvcEndpoint(RestartMvcEndpoint restartEndpoint) {
return restartEndpoint.getPauseEndpoint();
}
@Bean
public MvcEndpoint resumeMvcEndpoint(RestartMvcEndpoint restartEndpoint) {
return restartEndpoint.getResumeEndpoint();
}
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.platform.config.client;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -29,6 +30,8 @@ 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.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;
@@ -38,6 +41,7 @@ import org.springframework.util.ReflectionUtils;
*
*/
@ConfigurationProperties(prefix = "endpoints.refresh", ignoreUnknownFields = false)
@ManagedResource
public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> {
private ConfigurableApplicationContext context;
@@ -49,18 +53,23 @@ public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> {
this.context = context;
this.bootstrap = bootstrap;
}
@Override
public Collection<String> invoke() {
@ManagedOperation
public synchronized String[] refresh() {
Map<String, Object> before = extract(context.getEnvironment().getPropertySources());
bootstrap.initialize(context);
Set<String> keys = changes(before,
extract(context.getEnvironment().getPropertySources())).keySet();
if (keys.isEmpty()) {
return keys;
return new String[0];
}
context.publishEvent(new EnvironmentChangeEvent(keys));
return keys;
return keys.toArray(new String[keys.size()]);
}
@Override
public Collection<String> invoke() {
return Arrays.asList(refresh());
}
private Map<String, Object> changes(Map<String, Object> before,

View File

@@ -20,11 +20,15 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.endpoint.AbstractEndpoint;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.util.ClassUtils;
/**
@@ -37,6 +41,7 @@ import org.springframework.util.ClassUtils;
*
*/
@ConfigurationProperties("endpoints.restart")
@ManagedResource
public class RestartEndpoint extends AbstractEndpoint<Boolean> implements
ApplicationListener<ApplicationPreparedEvent> {
@@ -79,7 +84,48 @@ public class RestartEndpoint extends AbstractEndpoint<Boolean> implements
return false;
}
}
public Endpoint<Boolean> getPauseEndpoint() {
return new PauseEndpoint();
}
public Endpoint<Boolean> getResumeEndpoint() {
return new ResumeEndpoint();
}
private class PauseEndpoint extends AbstractEndpoint<Boolean> {
public PauseEndpoint() {
super("pause", true, true);
}
@Override
public Boolean invoke() {
if (isRunning()) {
pause();
return true;
}
return false;
}
}
private class ResumeEndpoint extends AbstractEndpoint<Boolean> {
public ResumeEndpoint() {
super("resume", true, true);
}
@Override
public Boolean invoke() {
if (!isRunning()) {
resume();
return true;
}
return false;
}
}
@ManagedOperation
public synchronized ConfigurableApplicationContext restart() {
if (context != null) {
context.close();
@@ -90,6 +136,28 @@ public class RestartEndpoint extends AbstractEndpoint<Boolean> implements
}
return context;
}
@ManagedAttribute
public boolean isRunning() {
if (context != null) {
return context.isRunning();
}
return false;
}
@ManagedOperation
public synchronized void pause() {
if (context != null) {
context.stop();
}
}
@ManagedOperation
public synchronized void resume() {
if (context != null) {
context.start();
}
}
private void overrideClassLoaderForRestart() {
ClassUtils.overrideThreadContextClassLoader(application.getClass().getClassLoader());

View File

@@ -18,7 +18,9 @@ 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.web.bind.annotation.RequestMapping;
@@ -55,5 +57,34 @@ public class RestartMvcEndpoint extends EndpointMvcAdapter {
return Collections.singletonMap(
"message", "Restarting");
}
public MvcEndpoint getPauseEndpoint() {
return new GenericPostableMvcEndpoint(((RestartEndpoint)getDelegate()).getPauseEndpoint());
}
public MvcEndpoint getResumeEndpoint() {
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();
}
}
}