From 21e9fc2961f3a6d24fd1c38d6eae3869a1136074 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 27 Jun 2014 08:33:55 +0100 Subject: [PATCH] Add Spring Integration to shutdown --- spring-platform-config-client/pom.xml | 5 ++ .../RefreshAutoConfiguration.java | 35 +++++++++-- .../config/client/RefreshEndpoint.java | 3 + .../context/restart/RestartEndpoint.java | 59 +++++++++++++++++-- 4 files changed, 90 insertions(+), 12 deletions(-) diff --git a/spring-platform-config-client/pom.xml b/spring-platform-config-client/pom.xml index 3eca7d3d..8971f6ca 100644 --- a/spring-platform-config-client/pom.xml +++ b/spring-platform-config-client/pom.xml @@ -41,6 +41,11 @@ spring-boot-starter-web true + + org.springframework.integration + spring-integration-jmx + true + org.springframework.boot spring-boot-starter-actuator diff --git a/spring-platform-config-client/src/main/java/org/springframework/platform/autoconfigure/RefreshAutoConfiguration.java b/spring-platform-config-client/src/main/java/org/springframework/platform/autoconfigure/RefreshAutoConfiguration.java index 55636aae..f05e4354 100644 --- a/spring-platform-config-client/src/main/java/org/springframework/platform/autoconfigure/RefreshAutoConfiguration.java +++ b/spring-platform-config-client/src/main/java/org/springframework/platform/autoconfigure/RefreshAutoConfiguration.java @@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetaData; @@ -35,6 +36,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.integration.monitor.IntegrationMBeanExporter; import org.springframework.platform.bootstrap.config.ConfigServiceBootstrapConfiguration; import org.springframework.platform.config.client.RefreshEndpoint; import org.springframework.platform.context.environment.EnvironmentManager; @@ -83,10 +85,31 @@ public class RefreshAutoConfiguration { @ConditionalOnClass(Endpoint.class) protected static class RefreshEndpointsConfiguration { - @Bean - @ConditionalOnMissingBean - public RestartEndpoint restartEndpoint() { - return new RestartEndpoint(); + @ConditionalOnClass(IntegrationMBeanExporter.class) + protected static class RefreshEndpointWithIntegration { + + @Autowired + private IntegrationMBeanExporter exporter; + + @Bean + @ConditionalOnMissingBean + public RestartEndpoint restartEndpoint() { + RestartEndpoint endpoint = new RestartEndpoint(); + if (exporter!=null) { + endpoint.setIntegrationMBeanExporter(exporter); + } + return endpoint; + } + } + + @ConditionalOnMissingClass(name="org.springframework.integration.monitor.IntegrationMBeanExporter") + protected static class RefreshEndpointWithoutIntegration { + + @Bean + @ConditionalOnMissingBean + public RestartEndpoint restartEndpoint() { + return new RestartEndpoint(); + } } @Bean @@ -94,13 +117,13 @@ public class RefreshAutoConfiguration { public Endpoint pauseEndpoint(RestartEndpoint restartEndpoint) { return restartEndpoint.getPauseEndpoint(); } - + @Bean @ConfigurationProperties("endpoints.resume") public Endpoint resumeEndpoint(RestartEndpoint restartEndpoint) { return restartEndpoint.getResumeEndpoint(); } - + @Configuration @ConditionalOnExpression("${endpoints.refresh.enabled:true}") @ConditionalOnBean(ConfigServiceBootstrapConfiguration.class) diff --git a/spring-platform-config-client/src/main/java/org/springframework/platform/config/client/RefreshEndpoint.java b/spring-platform-config-client/src/main/java/org/springframework/platform/config/client/RefreshEndpoint.java index 18b5b247..b3ce853b 100644 --- a/spring-platform-config-client/src/main/java/org/springframework/platform/config/client/RefreshEndpoint.java +++ b/spring-platform-config-client/src/main/java/org/springframework/platform/config/client/RefreshEndpoint.java @@ -24,6 +24,8 @@ 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.context.properties.ConfigurationProperties; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.CompositePropertySource; @@ -58,6 +60,7 @@ public class RefreshEndpoint extends AbstractEndpoint> { public synchronized String[] refresh() { Map before = extract(context.getEnvironment().getPropertySources()); bootstrap.initialize(context); + new ConfigFileApplicationListener().onApplicationEvent(new ApplicationEnvironmentPreparedEvent(null, null, context.getEnvironment())); Set keys = changes(before, extract(context.getEnvironment().getPropertySources())).keySet(); if (keys.isEmpty()) { diff --git a/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartEndpoint.java b/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartEndpoint.java index be30f19c..92f53bc8 100644 --- a/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartEndpoint.java +++ b/spring-platform-config-client/src/main/java/org/springframework/platform/context/restart/RestartEndpoint.java @@ -26,6 +26,7 @@ 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.integration.monitor.IntegrationMBeanExporter; import org.springframework.jmx.export.annotation.ManagedAttribute; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; @@ -59,6 +60,36 @@ public class RestartEndpoint extends AbstractEndpoint implements private ApplicationPreparedEvent event; + private IntegrationShutdown integrationShutdown; + + private boolean forceShutdown; + + private long timeout; + + @ManagedAttribute + public boolean isForceShutdown() { + return forceShutdown; + } + + public void setForceShutdown(boolean forceShutdown) { + this.forceShutdown = forceShutdown; + } + + @ManagedAttribute + public long getTimeout() { + return timeout; + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + public void setIntegrationMBeanExporter(IntegrationMBeanExporter exporter) { + if (exporter != null) { + this.integrationShutdown = new IntegrationShutdown(exporter); + } + } + @Override public void onApplicationEvent(ApplicationPreparedEvent input) { event = (ApplicationPreparedEvent) input; @@ -84,17 +115,17 @@ public class RestartEndpoint extends AbstractEndpoint implements return false; } } - + public Endpoint getPauseEndpoint() { return new PauseEndpoint(); } - + public Endpoint getResumeEndpoint() { return new ResumeEndpoint(); } - + private class PauseEndpoint extends AbstractEndpoint { - + public PauseEndpoint() { super("pause", true, true); } @@ -110,7 +141,7 @@ public class RestartEndpoint extends AbstractEndpoint implements } private class ResumeEndpoint extends AbstractEndpoint { - + public ResumeEndpoint() { super("resume", true, true); } @@ -128,6 +159,9 @@ public class RestartEndpoint extends AbstractEndpoint implements @ManagedOperation public synchronized ConfigurableApplicationContext restart() { if (context != null) { + if (integrationShutdown != null) { + integrationShutdown.stop(forceShutdown, timeout); + } context.close(); // If running in a webapp then the context classloader is probably going to // die so we need to revert to a safe place before starting again @@ -136,7 +170,7 @@ public class RestartEndpoint extends AbstractEndpoint implements } return context; } - + @ManagedAttribute public boolean isRunning() { if (context != null) { @@ -163,4 +197,17 @@ public class RestartEndpoint extends AbstractEndpoint implements ClassUtils.overrideThreadContextClassLoader(application.getClass().getClassLoader()); } + private class IntegrationShutdown { + + private IntegrationMBeanExporter exporter; + + public IntegrationShutdown(IntegrationMBeanExporter exporter) { + this.exporter = exporter; + } + + public void stop(boolean force, long timeout) { + exporter.stopActiveComponents(force, timeout); + } + } + }