Expose additional admin features
Improve SpringApplicationAdminMXBean to expose additional information: * Whether the application uses an embedded container * The properties exposed by the `Environment` This allows to know if the application is web-based and the HTTP port on which it is running. Closes gh-3067
This commit is contained in:
parent
c177a774a5
commit
b5d49b3099
|
|
@ -30,10 +30,18 @@ import org.junit.Rule;
|
|||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
|
||||
import org.springframework.boot.test.EnvironmentTestUtils;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
|
|
@ -52,7 +60,7 @@ public class SpringApplicationAdminJmxAutoConfigurationTests {
|
|||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
private MBeanServer mBeanServer;
|
||||
|
||||
|
|
@ -104,6 +112,22 @@ public class SpringApplicationAdminJmxAutoConfigurationTests {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void registerWithSimpleWebApp() throws Exception {
|
||||
this.context = new SpringApplicationBuilder()
|
||||
.sources(
|
||||
EmbeddedServletContainerAutoConfiguration.class,
|
||||
ServerPropertiesAutoConfiguration.class, DispatcherServletAutoConfiguration.class,
|
||||
JmxAutoConfiguration.class, SpringApplicationAdminJmxAutoConfiguration.class)
|
||||
.run("--" + ENABLE_ADMIN_PROP, "--server.port=0");
|
||||
assertTrue(this.context instanceof EmbeddedWebApplicationContext);
|
||||
assertEquals(true, this.mBeanServer.getAttribute(createDefaultObjectName(), "EmbeddedWebApplication"));
|
||||
int expected = ((EmbeddedWebApplicationContext) this.context).getEmbeddedServletContainer().getPort();
|
||||
String actual = getProperty(createDefaultObjectName(), "local.server.port");
|
||||
assertEquals(String.valueOf(expected), actual);
|
||||
}
|
||||
|
||||
private ObjectName createDefaultObjectName() {
|
||||
return createObjectName(DEFAULT_JMX_NAME);
|
||||
}
|
||||
|
|
@ -117,6 +141,11 @@ public class SpringApplicationAdminJmxAutoConfigurationTests {
|
|||
}
|
||||
}
|
||||
|
||||
private String getProperty(ObjectName objectName, String key) throws Exception {
|
||||
return (String) this.mBeanServer.invoke(objectName, "getProperty",
|
||||
new Object[]{key}, new String[]{String.class.getName()});
|
||||
}
|
||||
|
||||
private void load(String... environment) {
|
||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
|
||||
|
|
|
|||
|
|
@ -228,6 +228,9 @@ It is possible to enable admin-related features for the application by specifyin
|
|||
on the platform `MBeanServer`. You could use this feature to administer your Spring Boot
|
||||
application remotely. This could also be useful for any service wrapper implementation.
|
||||
|
||||
TIP: If you want to know on which HTTP port the application is running, get the property
|
||||
with key `local.server.port`.
|
||||
|
||||
NOTE: Take care when enabling this feature as the MBean exposes a method to shutdown the
|
||||
application.
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,23 @@ public interface SpringApplicationAdminMXBean {
|
|||
*/
|
||||
boolean isReady();
|
||||
|
||||
/**
|
||||
* Specify if the application runs in an embedded web container. Can return
|
||||
* {@code null} if that information is not yet available. It is preferable to
|
||||
* wait for the application to be {@link #isReady() ready}.
|
||||
* @return {@code true} if the application runs in an embedded web container
|
||||
* @see #isReady()
|
||||
*/
|
||||
boolean isEmbeddedWebApplication();
|
||||
|
||||
/**
|
||||
* Return the value of the specified key from the application
|
||||
* {@link org.springframework.core.env.Environment Environment}.
|
||||
* @param key the property key
|
||||
* @return the property value or {@code null} if it does not exist
|
||||
*/
|
||||
String getProperty(String key);
|
||||
|
||||
/**
|
||||
* Shutdown the application.
|
||||
* @see org.springframework.context.ConfigurableApplicationContext#close()
|
||||
|
|
|
|||
|
|
@ -27,11 +27,15 @@ import org.apache.commons.logging.LogFactory;
|
|||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.context.embedded.EmbeddedWebApplicationContext;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
|
|
@ -42,12 +46,14 @@ import org.springframework.util.Assert;
|
|||
* @since 1.3.0
|
||||
*/
|
||||
public class SpringApplicationAdminMXBeanRegistrar implements ApplicationContextAware,
|
||||
InitializingBean, DisposableBean, ApplicationListener<ApplicationReadyEvent> {
|
||||
EnvironmentAware, InitializingBean, DisposableBean, ApplicationListener<ApplicationReadyEvent> {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SpringApplicationAdmin.class);
|
||||
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
private Environment environment = new StandardEnvironment();
|
||||
|
||||
private final ObjectName objectName;
|
||||
|
||||
private boolean ready = false;
|
||||
|
|
@ -65,6 +71,11 @@ public class SpringApplicationAdminMXBeanRegistrar implements ApplicationContext
|
|||
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
this.ready = true;
|
||||
|
|
@ -92,6 +103,17 @@ public class SpringApplicationAdminMXBeanRegistrar implements ApplicationContext
|
|||
return SpringApplicationAdminMXBeanRegistrar.this.ready;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmbeddedWebApplication() {
|
||||
return (applicationContext != null
|
||||
&& applicationContext instanceof EmbeddedWebApplicationContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProperty(String key) {
|
||||
return environment.getProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
logger.info("Application shutdown requested.");
|
||||
|
|
|
|||
|
|
@ -29,15 +29,15 @@ import org.junit.Rule;
|
|||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringApplicationAdminMXBeanRegistrar}.
|
||||
|
|
@ -76,8 +76,7 @@ public class SpringApplicationAdminMXBeanRegistrarTests {
|
|||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
try {
|
||||
assertFalse("Application should not be ready yet",
|
||||
isCurrentApplicationReady(objectName));
|
||||
assertThat(isApplicationReady(objectName), is(false));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(
|
||||
|
|
@ -86,8 +85,19 @@ public class SpringApplicationAdminMXBeanRegistrarTests {
|
|||
}
|
||||
});
|
||||
this.context = application.run();
|
||||
assertTrue("application should be ready now",
|
||||
isCurrentApplicationReady(objectName));
|
||||
assertThat(isApplicationReady(objectName), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void environmentIsExposed() {
|
||||
final ObjectName objectName = createObjectName(OBJECT_NAME);
|
||||
SpringApplication application = new SpringApplication(Config.class);
|
||||
application.setWebEnvironment(false);
|
||||
this.context = application.run("--foo.bar=blam");
|
||||
assertThat(isApplicationReady(objectName), is(true));
|
||||
assertThat(isApplicationEmbeddedWebApplication(objectName), is(false));
|
||||
assertThat(getProperty(objectName, "foo.bar"), is("blam"));
|
||||
assertThat(getProperty(objectName, "does.not.exist.test"), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -96,16 +106,36 @@ public class SpringApplicationAdminMXBeanRegistrarTests {
|
|||
SpringApplication application = new SpringApplication(Config.class);
|
||||
application.setWebEnvironment(false);
|
||||
this.context = application.run();
|
||||
assertTrue("application should be running", this.context.isRunning());
|
||||
assertThat(this.context.isRunning(), is(true));
|
||||
invokeShutdown(objectName);
|
||||
assertFalse("application should not be running", this.context.isRunning());
|
||||
assertThat(this.context.isRunning(), is(false));
|
||||
this.thrown.expect(InstanceNotFoundException.class); // JMX cleanup
|
||||
this.mBeanServer.getObjectInstance(objectName);
|
||||
}
|
||||
|
||||
private Boolean isCurrentApplicationReady(ObjectName objectName) {
|
||||
private Boolean isApplicationReady(ObjectName objectName) {
|
||||
return getAttribute(objectName, Boolean.class, "Ready");
|
||||
}
|
||||
|
||||
private Boolean isApplicationEmbeddedWebApplication(ObjectName objectName) {
|
||||
return getAttribute(objectName, Boolean.class, "EmbeddedWebApplication");
|
||||
}
|
||||
|
||||
private String getProperty(ObjectName objectName, String key) {
|
||||
try {
|
||||
return (Boolean) this.mBeanServer.getAttribute(objectName, "Ready");
|
||||
return (String) this.mBeanServer.invoke(objectName, "getProperty",
|
||||
new Object[] {key}, new String[] {String.class.getName()});
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T getAttribute(ObjectName objectName, Class<T> type, String attribute) {
|
||||
try {
|
||||
Object value = this.mBeanServer.getAttribute(objectName, attribute);
|
||||
assertThat((value == null || type.isInstance(value)), is(true));
|
||||
return type.cast(value);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex.getMessage(), ex);
|
||||
|
|
|
|||
Loading…
Reference in New Issue