From 331e79002620f458f2ae4b51af8147242e700af1 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 24 Feb 2017 09:33:51 +0000 Subject: [PATCH] Ensure there is a single bootstrap parent context Only one neds to be created, and once it is in place in the hierarchy it should be usable by all the child contexts that get added. Fixes gh-153 --- .../BootstrapApplicationListener.java | 5 + ...tHigherPriorityBootstrapConfiguration.java | 4 + .../config/BootstrapConfigurationTests.java | 14 +++ ...trapListenerHierarchyIntegrationTests.java | 100 ++++++++++++++++++ 4 files changed, 123 insertions(+) create mode 100644 spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapListenerHierarchyIntegrationTests.java diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/BootstrapApplicationListener.java b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/BootstrapApplicationListener.java index 764289413b..648c536190 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/BootstrapApplicationListener.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/BootstrapApplicationListener.java @@ -81,6 +81,11 @@ public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) { if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) { return; } + for (ApplicationContextInitializer initializer : event.getSpringApplication().getInitializers()) { + if (initializer instanceof ParentContextApplicationContextInitializer) { + return; + } + } ConfigurableApplicationContext context = bootstrapServiceContext(environment, event.getSpringApplication()); apply(context, event.getSpringApplication(), environment); diff --git a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/TestHigherPriorityBootstrapConfiguration.java b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/TestHigherPriorityBootstrapConfiguration.java index 2494a5b690..90aa8b5c72 100644 --- a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/TestHigherPriorityBootstrapConfiguration.java +++ b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/TestHigherPriorityBootstrapConfiguration.java @@ -1,5 +1,6 @@ package org.springframework.cloud.bootstrap; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import org.springframework.core.Ordered; @@ -12,8 +13,11 @@ public class TestHigherPriorityBootstrapConfiguration { static final AtomicReference> firstToBeCreated = new AtomicReference<>(); + + public static final AtomicInteger count = new AtomicInteger(); public TestHigherPriorityBootstrapConfiguration() { + count.incrementAndGet(); firstToBeCreated.compareAndSet(null, TestHigherPriorityBootstrapConfiguration.class); } diff --git a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java index 6267fcd1df..87ad1f3afe 100644 --- a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java +++ b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java @@ -28,6 +28,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.cloud.bootstrap.TestHigherPriorityBootstrapConfiguration; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; @@ -42,6 +43,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; /** @@ -270,6 +272,18 @@ public void environmentEnrichedOnceWhenSharedWithChildContext() { assertEquals(0, sources.precedenceOf(bootstrap)); } + @Test + public void onlyOneBootstrapContext() { + TestHigherPriorityBootstrapConfiguration.count.set(0); + PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); + this.context = new SpringApplicationBuilder().sources(BareConfiguration.class) + .child(BareConfiguration.class).web(false).run(); + assertEquals(1, TestHigherPriorityBootstrapConfiguration.count.get()); + assertNotNull(context.getParent()); + assertEquals("bootstrap", context.getParent().getParent().getId()); + assertNull(context.getParent().getParent().getParent()); + } + @Test public void environmentEnrichedInParentContext() { PropertySourceConfiguration.MAP.put("bootstrap.foo", "bar"); diff --git a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapListenerHierarchyIntegrationTests.java b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapListenerHierarchyIntegrationTests.java new file mode 100644 index 0000000000..f2ecf0586c --- /dev/null +++ b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapListenerHierarchyIntegrationTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2013-2017 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.cloud.bootstrap.config; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +import org.junit.Test; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Integration tests for Bootstrap Listener's functionality of adding a bootstrap context + * as the root Application Context + * + * @author Biju Kunjummen + */ +public class BootstrapListenerHierarchyIntegrationTests { + + @Test + public void shouldAddInABootstrapContext() { + ConfigurableApplicationContext context = new SpringApplicationBuilder() + .sources(BasicConfiguration.class).web(false).run(); + + assertNotNull(context.getParent()); + } + + @Test + public void shouldAddInOneBootstrapForABasicParentChildHierarchy() { + ConfigurableApplicationContext context = new SpringApplicationBuilder() + .sources(RootConfiguration.class).web(false) + .child(BasicConfiguration.class).web(false).run(); + + // Should be RootConfiguration based context + ConfigurableApplicationContext parent = (ConfigurableApplicationContext) context + .getParent(); + assertEquals("rootBean", parent.getBean("rootBean", String.class)); + + // Parent should have the bootstrap context as parent + assertNotNull(parent.getParent()); + + ConfigurableApplicationContext bootstrapContext = (ConfigurableApplicationContext) parent + .getParent(); + + // Bootstrap should be the root, there should be no other parent + assertNull(bootstrapContext.getParent()); + } + + @Test + public void shouldAddInOneBootstrapForSiblingsBasedHierarchy() { + ConfigurableApplicationContext context = new SpringApplicationBuilder() + .sources(RootConfiguration.class).web(false) + .child(BasicConfiguration.class).web(false) + .sibling(BasicConfiguration.class).web(false).run(); + + // Should be RootConfiguration based context + ConfigurableApplicationContext parent = (ConfigurableApplicationContext) context + .getParent(); + assertEquals("rootBean", parent.getBean("rootBean", String.class)); + + // Parent should have the bootstrap context as parent + assertNotNull(parent.getParent()); + + ConfigurableApplicationContext bootstrapContext = (ConfigurableApplicationContext) parent + .getParent(); + + // Bootstrap should be the root, there should be no other parent + assertNull(bootstrapContext.getParent()); + } + + @Configuration + static class BasicConfiguration { + } + + @Configuration + static class RootConfiguration { + + @Bean + public String rootBean() { + return "rootBean"; + } + } +} \ No newline at end of file