From c2db9fa3852534133c957b639c78fc4a77eb8bf7 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 12 Jul 2016 09:13:36 +0100 Subject: [PATCH] Update admin MBean to only be ready when its own context is ready Previously, if there was a hierarchy of SpringApplications, the admin MBean would report that the application was ready as soon as any application in the hierarchy was ready. This could lead to a client trying to query a property in the environment before it's available. This commit updates the MBean registrar to that the MBean only reports that the application is ready when the context that contains the registrar has refreshed and fired its ApplicationReadyEvent. Closes gh-6362 --- ...SpringApplicationAdminMXBeanRegistrar.java | 7 +++-- ...gApplicationAdminMXBeanRegistrarTests.java | 27 ++++++++++++++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrar.java b/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrar.java index 81dbf54f983..cc9caafdf2d 100644 --- a/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrar.java +++ b/spring-boot/src/main/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -44,6 +44,7 @@ import org.springframework.util.Assert; * {@link MBeanServer}. * * @author Stephane Nicoll + * @author Andy Wilkinson * @since 1.3.0 */ public class SpringApplicationAdminMXBeanRegistrar @@ -80,7 +81,9 @@ public class SpringApplicationAdminMXBeanRegistrar @Override public void onApplicationEvent(ApplicationReadyEvent event) { - this.ready = true; + if (this.applicationContext.equals(event.getApplicationContext())) { + this.ready = true; + } } @Override diff --git a/spring-boot/src/test/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrarTests.java b/spring-boot/src/test/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrarTests.java index 7db1fb689d4..941a307f983 100644 --- a/spring-boot/src/test/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrarTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/admin/SpringApplicationAdminMXBeanRegistrarTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 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. @@ -30,20 +30,26 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.boot.SpringApplication; +import org.springframework.boot.context.event.ApplicationReadyEvent; 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 org.springframework.test.util.ReflectionTestUtils; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; /** * Tests for {@link SpringApplicationAdminMXBeanRegistrar}. * * @author Stephane Nicoll + * @author Andy Wilkinson */ public class SpringApplicationAdminMXBeanRegistrarTests { @@ -89,6 +95,25 @@ public class SpringApplicationAdminMXBeanRegistrarTests { assertThat(isApplicationReady(objectName), is(true)); } + @Test + public void eventsFromOtherContextsAreIgnored() throws MalformedObjectNameException { + SpringApplicationAdminMXBeanRegistrar registrar = new SpringApplicationAdminMXBeanRegistrar( + OBJECT_NAME); + ConfigurableApplicationContext context = mock( + ConfigurableApplicationContext.class); + registrar.setApplicationContext(context); + registrar.onApplicationEvent(new ApplicationReadyEvent(new SpringApplication(), + null, mock(ConfigurableApplicationContext.class))); + assertFalse(isApplicationReady(registrar)); + registrar.onApplicationEvent( + new ApplicationReadyEvent(new SpringApplication(), null, context)); + assertTrue(isApplicationReady(registrar)); + } + + private boolean isApplicationReady(SpringApplicationAdminMXBeanRegistrar registrar) { + return (Boolean) ReflectionTestUtils.getField(registrar, "ready"); + } + @Test public void environmentIsExposed() { final ObjectName objectName = createObjectName(OBJECT_NAME);