diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationDecision.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationDecision.java index 683363e031..25c0da463c 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationDecision.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationDecision.java @@ -20,37 +20,39 @@ import org.springframework.boot.autoconfigure.condition.Outcome; /** * Collects details about decision made during autoconfiguration (pass or fail) - * + * * @author Greg Turnquist */ public class AutoConfigurationDecision { + private final String message; private final String classOrMethodName; private final Outcome outcome; - public AutoConfigurationDecision(String message, String classOrMethodName, Outcome outcome) { + public AutoConfigurationDecision(String message, String classOrMethodName, + Outcome outcome) { this.message = message; this.classOrMethodName = classOrMethodName; this.outcome = outcome; } public String getMessage() { - return message; + return this.message; } public String getClassOrMethodName() { - return classOrMethodName; + return this.classOrMethodName; } public Outcome getOutcome() { - return outcome; + return this.outcome; } @Override public String toString() { - return "AutoConfigurationDecision{" + "message='" + message + '\'' - + ", classOrMethodName='" + classOrMethodName + '\'' + ", outcome=" - + outcome + '}'; + return "AutoConfigurationDecision{" + "message='" + this.message + '\'' + + ", classOrMethodName='" + this.classOrMethodName + '\'' + ", outcome=" + + this.outcome + '}'; } @Override @@ -62,10 +64,10 @@ public class AutoConfigurationDecision { AutoConfigurationDecision decision = (AutoConfigurationDecision) o; - if (message != null ? !message.equals(decision.message) + if (this.message != null ? !this.message.equals(decision.message) : decision.message != null) return false; - if (outcome != null ? !outcome.equals(decision.outcome) + if (this.outcome != null ? !this.outcome.equals(decision.outcome) : decision.outcome != null) return false; @@ -74,8 +76,8 @@ public class AutoConfigurationDecision { @Override public int hashCode() { - int result = message != null ? message.hashCode() : 0; - result = 31 * result + (outcome != null ? outcome.hashCode() : 0); + int result = this.message != null ? this.message.hashCode() : 0; + result = 31 * result + (this.outcome != null ? this.outcome.hashCode() : 0); return result; } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationReport.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationReport.java index 82978ff7aa..9806b2a916 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationReport.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationReport.java @@ -36,6 +36,7 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ConditionContext; import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.util.ClassUtils; /** * Bean used to gather autoconfiguration decisions, and then generate a collection of info @@ -56,7 +57,7 @@ public class AutoConfigurationReport implements ApplicationContextAware, private Map> autoconfigurationDecisions = new LinkedHashMap>(); private Map> positive = new LinkedHashMap>(); private Map> negative = new LinkedHashMap>(); - private ApplicationContext context; + private ConfigurableApplicationContext context; private boolean initialized = false; public static void registerDecision(ConditionContext context, String message, @@ -64,7 +65,7 @@ public class AutoConfigurationReport implements ApplicationContextAware, if (context.getBeanFactory().containsBeanDefinition(AUTO_CONFIGURATION_REPORT) || context.getBeanFactory().containsSingleton(AUTO_CONFIGURATION_REPORT)) { AutoConfigurationReport autoconfigurationReport = context.getBeanFactory() - .getBean(AutoConfigurationReport.class); + .getBean(AUTO_CONFIGURATION_REPORT, AutoConfigurationReport.class); autoconfigurationReport.registerDecision(message, classOrMethodName, outcome); } } @@ -120,7 +121,7 @@ public class AutoConfigurationReport implements ApplicationContextAware, @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.context = applicationContext; + this.context = (ConfigurableApplicationContext) applicationContext; } @Override @@ -133,17 +134,20 @@ public class AutoConfigurationReport implements ApplicationContextAware, synchronized (this) { if (!this.initialized) { this.initialized = true; - splitDecisionsIntoPositiveAndNegative(); - scanPositiveDecisionsForBeansBootCreated(); - if (this.context.getEnvironment().getProperty("debug", Boolean.class, - false)) { - logger.info("Created beans:"); - for (CreatedBeanInfo info : this.beansCreated) { - logger.info(info); - } - logger.info("Negative decisions:"); - for (String key : this.negative.keySet()) { - logger.info(key + ": " + this.negative.get(key)); + try { + splitDecisionsIntoPositiveAndNegative(); + scanPositiveDecisionsForBeansBootCreated(); + } + finally { + if (shouldLogReport()) { + logger.info("Created beans:"); + for (CreatedBeanInfo info : this.beansCreated) { + logger.info(info); + } + logger.info("Negative decisions:"); + for (String key : this.negative.keySet()) { + logger.info(key + ": " + this.negative.get(key)); + } } } } @@ -151,6 +155,11 @@ public class AutoConfigurationReport implements ApplicationContextAware, } } + private boolean shouldLogReport() { + return this.context.getEnvironment().getProperty("debug", Boolean.class, false) + || !this.context.isActive(); + } + /** * Scan the list of {@link AutoConfigurationDecision}'s, and if all outcomes true, * then put it on the positive list. Otherwise, put it on the negative list. @@ -194,21 +203,36 @@ public class AutoConfigurationReport implements ApplicationContextAware, for (AutoConfigurationDecision decision : this.autoconfigurationDecisions .get(key)) { for (String beanName : this.context.getBeanDefinitionNames()) { - Object bean = this.context.getBean(beanName); + Object bean = null; if (decision.getMessage().contains(beanName) && decision.getMessage().contains("matched")) { - boolean anyMethodsAreBeans = false; - for (Method method : bean.getClass().getMethods()) { - if (this.context.containsBean(method.getName())) { - this.beansCreated.add(new CreatedBeanInfo(method - .getName(), method.getReturnType(), this.positive - .get(key))); - anyMethodsAreBeans = true; + try { + bean = this.context.getBean(beanName); + boolean anyMethodsAreBeans = false; + for (Method method : bean.getClass().getMethods()) { + if (this.context.containsBean(method.getName())) { + this.beansCreated.add(new CreatedBeanInfo(method + .getName(), method.getReturnType(), + this.positive.get(key))); + anyMethodsAreBeans = true; + } + } + + if (!anyMethodsAreBeans) { + this.beansCreated.add(new CreatedBeanInfo(beanName, bean + .getClass(), this.positive.get(key))); } } - - if (!anyMethodsAreBeans) { - this.beansCreated.add(new CreatedBeanInfo(beanName, bean, + catch (RuntimeException e) { + Class type = null; + ConfigurableApplicationContext configurable = this.context; + String beanClassName = configurable.getBeanFactory() + .getBeanDefinition(beanName).getBeanClassName(); + if (beanClassName != null) { + type = ClassUtils.resolveClassName(beanClassName, + configurable.getClassLoader()); + } + this.beansCreated.add(new CreatedBeanInfo(beanName, type, this.positive.get(key))); } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/CreatedBeanInfo.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/CreatedBeanInfo.java index fbb19eee7a..50b8b40fb2 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/CreatedBeanInfo.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/CreatedBeanInfo.java @@ -29,12 +29,6 @@ public class CreatedBeanInfo { private final Class type; private final List decisions; - public CreatedBeanInfo(String beanName, Object bean, List decisions) { - this.name = beanName; - this.type = bean.getClass(); - this.decisions = decisions; - } - public CreatedBeanInfo(String beanName, Class declaredBeanType, List decisions) { this.name = beanName; diff --git a/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index 098f7db1b9..17a7acbdc9 100644 --- a/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -168,7 +168,7 @@ public class SpringApplication { private boolean webEnvironment; - private List> initializers; + private Collection> initializers; private Map defaultProperties; @@ -207,7 +207,7 @@ public class SpringApplication { this.initialSources.addAll(Arrays.asList(sources)); } this.webEnvironment = deduceWebEnvironment(); - this.initializers = new ArrayList>(); + this.initializers = new LinkedHashSet>(); this.initializers.addAll(getSpringFactoriesApplicationContextInitializers()); this.mainApplicationClass = deduceMainApplicationClass(); } @@ -716,15 +716,12 @@ public class SpringApplication { } /** - * Returns a mutable list of the {@link ApplicationContextInitializer}s that will be + * Returns readonly list of the {@link ApplicationContextInitializer}s that will be * applied to the Spring {@link ApplicationContext}. * @return the initializers */ public List> getInitializers() { - List> initializers = new ArrayList>( - getSpringFactoriesApplicationContextInitializers()); - initializers.addAll(this.initializers); - return initializers; + return new ArrayList>(this.initializers); } /** diff --git a/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java b/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java index 0627d65604..c14179b411 100644 --- a/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java +++ b/spring-boot/src/main/java/org/springframework/boot/builder/SpringApplicationBuilder.java @@ -70,6 +70,7 @@ public class SpringApplicationBuilder { private Map defaultProperties = new LinkedHashMap(); private ConfigurableEnvironment environment; private Set additionalProfiles = new LinkedHashSet(); + private Set> initializers = new LinkedHashSet>(); public SpringApplicationBuilder(Object... sources) { this.application = new SpringApplication(sources); @@ -466,12 +467,13 @@ public class SpringApplicationBuilder { Set> target = new LinkedHashSet>(); if (prepend) { target.addAll(Arrays.asList(initializers)); - target.addAll(this.application.getInitializers()); + target.addAll(this.initializers); } else { - target.addAll(this.application.getInitializers()); + target.addAll(this.initializers); target.addAll(Arrays.asList(initializers)); } + this.initializers = target; this.application.setInitializers(target); } diff --git a/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java b/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java index 0f330280ad..b15e4df6eb 100644 --- a/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/builder/SpringApplicationBuilderTests.java @@ -34,6 +34,7 @@ import org.springframework.util.StringUtils; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Mockito.spy; @@ -169,6 +170,14 @@ public class SpringApplicationBuilderTests { any(ApplicationContext.class)); } + @Test + public void initializersCreatedOnce() throws Exception { + SpringApplicationBuilder application = new SpringApplicationBuilder( + ExampleConfig.class).web(false); + this.context = application.run(); + assertEquals(7, application.application().getInitializers().size()); + } + @Configuration static class ExampleConfig {