diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
index 37a89f17c4..9b087f6712 100644
--- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
+++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc
@@ -47,7 +47,6 @@ content into your application. Rather, pick only the properties that you need.
spring.aop.proxy-target-class=true # Whether subclass-based (CGLIB) proxies are to be created (true), as opposed to standard Java interface-based proxies (false).
# IDENTITY ({sc-spring-boot}/context/ContextIdApplicationContextInitializer.{sc-ext}[ContextIdApplicationContextInitializer])
- spring.application.index= # Application index.
spring.application.name= # Application name.
# ADMIN ({sc-spring-boot-autoconfigure}/admin/SpringApplicationAdminJmxAutoConfiguration.{sc-ext}[SpringApplicationAdminJmxAutoConfiguration])
diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/ContextIdApplicationContextInitializer.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/ContextIdApplicationContextInitializer.java
index 9d791125a4..be1b8ce4c3 100644
--- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/ContextIdApplicationContextInitializer.java
+++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/ContextIdApplicationContextInitializer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 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.
@@ -16,6 +16,8 @@
package org.springframework.boot.context;
+import java.util.concurrent.atomic.AtomicLong;
+
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
@@ -24,73 +26,19 @@ import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.StringUtils;
/**
- * {@link ApplicationContextInitializer} that set the Spring
- * {@link ApplicationContext#getId() ApplicationContext ID}. The following environment
- * properties will be consulted to create the ID:
- *
- * - spring.application.name
- * - vcap.application.name
- * - spring.config.name
- *
- * If no property is set the ID 'application' will be used.
- *
- *
- * In addition the following environment properties will be consulted to append a relevant
- * port or index:
- *
- *
- * - spring.application.index
- * - vcap.application.instance_index
- * - PORT
- *
+ * {@link ApplicationContextInitializer} that sets the Spring
+ * {@link ApplicationContext#getId() ApplicationContext ID}. The
+ * {@code spring.application.name} property is used to create the ID. If the property is
+ * not set {@code application} is used.
*
* @author Dave Syer
+ * @author Andy Wilkinson
*/
public class ContextIdApplicationContextInitializer implements
ApplicationContextInitializer, Ordered {
- /**
- * Placeholder pattern to resolve for application name. The following order is used to
- * find the name:
- *
- * - {@code spring.application.name}
- * - {@code vcap.application.name}
- * - {@code spring.config.name}
- *
- * This order allows the user defined name to take precedence over the platform
- * defined name. If no property is defined {@code 'application'} will be used.
- */
- private static final String NAME_PATTERN = "${spring.application.name:${vcap.application.name:${spring.config.name:application}}}";
-
- /**
- * Placeholder pattern to resolve for application index. The following order is used
- * to find the name:
- *
- * - {@code vcap.application.instance_index}
- * - {@code spring.application.index}
- * - {@code server.port}
- * - {@code PORT}
- *
- * This order favors a platform defined index over any user defined value.
- */
- private static final String INDEX_PATTERN = "${vcap.application.instance_index:${spring.application.index:${server.port:${PORT:null}}}}";
-
- private final String name;
-
private int order = Ordered.LOWEST_PRECEDENCE - 10;
- public ContextIdApplicationContextInitializer() {
- this(NAME_PATTERN);
- }
-
- /**
- * Create a new {@link ContextIdApplicationContextInitializer} instance.
- * @param name the name of the application (can include placeholders)
- */
- public ContextIdApplicationContextInitializer(String name) {
- this.name = name;
- }
-
public void setOrder(int order) {
this.order = order;
}
@@ -102,21 +50,46 @@ public class ContextIdApplicationContextInitializer implements
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
- applicationContext.setId(getApplicationId(applicationContext.getEnvironment()));
+ ContextId contextId = getContextId(applicationContext);
+ applicationContext.setId(contextId.getId());
+ applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(),
+ contextId);
+ }
+
+ private ContextId getContextId(ConfigurableApplicationContext applicationContext) {
+ ApplicationContext parent = applicationContext.getParent();
+ if (parent != null && parent.containsBean(ContextId.class.getName())) {
+ return parent.getBean(ContextId.class).createChildId();
+ }
+ return new ContextId(getApplicationId(applicationContext.getEnvironment()));
}
private String getApplicationId(ConfigurableEnvironment environment) {
- String name = environment.resolvePlaceholders(this.name);
- String index = environment.resolvePlaceholders(INDEX_PATTERN);
- String profiles = StringUtils
- .arrayToCommaDelimitedString(environment.getActiveProfiles());
- if (StringUtils.hasText(profiles)) {
- name = name + ":" + profiles;
+ String name = environment.getProperty("spring.application.name");
+ return StringUtils.hasText(name) ? name : "application";
+ }
+
+ /**
+ * The ID of a context.
+ */
+ class ContextId {
+
+ private final AtomicLong children = new AtomicLong(0);
+
+ private final String id;
+
+ ContextId(String id) {
+ this.id = id;
}
- if (!"null".equals(index)) {
- name = name + ":" + index;
+
+ ContextId createChildId() {
+ return new ContextId(this.id + "-" + this.children.incrementAndGet());
}
- return name;
+
+ String getId() {
+ return this.id;
+ }
+
}
}
diff --git a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index 2924562836..47a050ed7d 100644
--- a/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -143,12 +143,6 @@
"sourceType": "org.springframework.boot.context.ContextIdApplicationContextInitializer",
"description": "Application name."
},
- {
- "name": "spring.application.index",
- "type": "java.lang.Integer",
- "sourceType": "org.springframework.boot.context.ContextIdApplicationContextInitializer",
- "description": "Application index."
- },
{
"name": "spring.beaninfo.ignore",
"type": "java.lang.Boolean",
diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/ContextIdApplicationContextInitializerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/ContextIdApplicationContextInitializerTests.java
index 0bedae323a..a795ce2093 100644
--- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/ContextIdApplicationContextInitializerTests.java
+++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/ContextIdApplicationContextInitializerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2018 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.
@@ -16,6 +16,11 @@
package org.springframework.boot.context;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.After;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
@@ -33,50 +38,67 @@ public class ContextIdApplicationContextInitializerTests {
private final ContextIdApplicationContextInitializer initializer = new ContextIdApplicationContextInitializer();
+ private List contexts = new ArrayList<>();
+
+ @After
+ public void closeContexts() {
+ Collections.reverse(this.contexts);
+ this.contexts.forEach(ConfigurableApplicationContext::close);
+ }
+
@Test
- public void testDefaults() {
- ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
- this.initializer.initialize(context);
+ public void singleContextWithDefaultName() {
+ ConfigurableApplicationContext context = createContext(null);
assertThat(context.getId()).isEqualTo("application");
}
@Test
- public void testNameAndPort() {
- ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
- TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context,
- "spring.application.name=foo", "PORT=8080");
- this.initializer.initialize(context);
- assertThat(context.getId()).isEqualTo("foo:8080");
+ public void singleContextWithCustomName() {
+ ConfigurableApplicationContext context = createContext(null,
+ "spring.application.name=test");
+ assertThat(context.getId()).isEqualTo("test");
}
@Test
- public void testNameAndProfiles() {
- ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
- TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context,
- "spring.application.name=foo", "spring.profiles.active=spam,bar",
- "spring.application.index=12");
- this.initializer.initialize(context);
- assertThat(context.getId()).isEqualTo("foo:spam,bar:12");
+ public void linearHierarchy() {
+ ConfigurableApplicationContext grandparent = createContext(null);
+ ConfigurableApplicationContext parent = createContext(grandparent);
+ ConfigurableApplicationContext child = createContext(parent);
+ assertThat(child.getId()).isEqualTo("application-1-1");
}
@Test
- public void testCloudFoundry() {
- ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
- TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context,
- "spring.config.name=foo", "PORT=8080", "vcap.application.name=bar",
- "vcap.application.instance_index=2");
- this.initializer.initialize(context);
- assertThat(context.getId()).isEqualTo("bar:2");
+ public void complexHierarchy() {
+ ConfigurableApplicationContext grandparent = createContext(null);
+ ConfigurableApplicationContext parent1 = createContext(grandparent);
+ ConfigurableApplicationContext parent2 = createContext(grandparent);
+ ConfigurableApplicationContext child1_1 = createContext(parent1);
+ assertThat(child1_1.getId()).isEqualTo("application-1-1");
+ ConfigurableApplicationContext child1_2 = createContext(parent1);
+ assertThat(child1_2.getId()).isEqualTo("application-1-2");
+ ConfigurableApplicationContext child2_1 = createContext(parent2);
+ assertThat(child2_1.getId()).isEqualTo("application-2-1");
}
@Test
- public void testExplicitNameIsChosenInFavorOfCloudFoundry() {
+ public void contextWithParentWithNoContextIdFallsBackToDefaultId() {
+ ConfigurableApplicationContext parent = new AnnotationConfigApplicationContext();
+ this.contexts.add(parent);
+ parent.refresh();
+ assertThat(createContext(parent).getId()).isEqualTo("application");
+ }
+
+ private ConfigurableApplicationContext createContext(
+ ConfigurableApplicationContext parent, String... properties) {
ConfigurableApplicationContext context = new AnnotationConfigApplicationContext();
- TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context,
- "spring.application.name=spam", "spring.config.name=foo", "PORT=8080",
- "vcap.application.name=bar", "vcap.application.instance_index=2");
+ TestPropertySourceUtils.addInlinedPropertiesToEnvironment(context, properties);
+ if (parent != null) {
+ context.setParent(parent);
+ }
this.initializer.initialize(context);
- assertThat(context.getId()).isEqualTo("spam:2");
+ context.refresh();
+ this.contexts.add(context);
+ return context;
}
}