From 0c79c8913ffb1b7d8e10568c691fa15cb0f94972 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 4 Nov 2013 16:01:30 +0000 Subject: [PATCH] Ensure AutoConfigurationReport is always present --- .../AutoConfigurationReportEndpoint.java | 7 +-- .../EndpointAutoConfigurationTests.java | 6 +-- .../AutoConfigurationReportEndpointTests.java | 17 ++++--- .../report/AutoConfigurationReport.java | 20 +++++++- ...onReportApplicationContextInitializer.java | 48 +++++++++++++++++++ .../main/resources/META-INF/spring.factories | 2 + .../AutoConfigurationReportTests.java | 35 ++++++++------ .../ops/ui/SampleSecureApplication.java | 2 - 8 files changed, 108 insertions(+), 29 deletions(-) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationReportApplicationContextInitializer.java diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java index 9018185ae1c..8c373b4ec09 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpoint.java @@ -22,17 +22,18 @@ import org.springframework.boot.context.properties.ConfigurationProperties; /** * Endpoint to serve up autoconfiguration report if actuator is on the classpath. - * + * * @author Greg Turnquist */ @ConfigurationProperties(name = "endpoints.autoconfigurationreport", ignoreUnknownFields = false) -public class AutoConfigurationReportEndpoint extends AbstractEndpoint { +public class AutoConfigurationReportEndpoint extends + AbstractEndpoint { @Autowired private AutoConfigurationReport autoConfigurationReport; public AutoConfigurationReportEndpoint() { - super("/autoconfigurationreport"); + super("/auto"); } @Override diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java index e1576235032..a88cdad901a 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/EndpointAutoConfigurationTests.java @@ -29,7 +29,7 @@ import org.springframework.boot.actuate.endpoint.InfoEndpoint; import org.springframework.boot.actuate.endpoint.MetricsEndpoint; import org.springframework.boot.actuate.endpoint.ShutdownEndpoint; import org.springframework.boot.actuate.endpoint.TraceEndpoint; -import org.springframework.boot.autoconfigure.report.AutoConfigurationReportCreator; +import org.springframework.boot.autoconfigure.report.AutoConfigurationReport; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import static org.junit.Assert.assertEquals; @@ -74,12 +74,12 @@ public class EndpointAutoConfigurationTests { @Test public void autoconfigurationAuditEndpoints() { this.context = new AnnotationConfigApplicationContext(); - this.context.register(EndpointAutoConfiguration.class, AutoConfigurationReportCreator.class); + this.context.register(EndpointAutoConfiguration.class, + AutoConfigurationReport.class); this.context.refresh(); assertNotNull(this.context.getBean(AutoConfigurationReportEndpoint.class)); } - @Test public void testInfoEndpointConfiguration() throws Exception { this.context = new AnnotationConfigApplicationContext(); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpointTests.java index 0c06c8be252..4a50c2e4c4e 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/AutoConfigurationReportEndpointTests.java @@ -16,28 +16,33 @@ package org.springframework.boot.actuate.endpoint; -import org.springframework.boot.autoconfigure.report.EnableAutoConfigurationReport; +import org.springframework.boot.autoconfigure.report.AutoConfigurationReport; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Tests for {@link AutoConfigurationReportEndpoint}. - * + * * @author Greg Turnquist */ -public class AutoConfigurationReportEndpointTests extends AbstractEndpointTests { +public class AutoConfigurationReportEndpointTests extends + AbstractEndpointTests { public AutoConfigurationReportEndpointTests() { - super(Config.class, AutoConfigurationReportEndpoint.class, - "/autoconfigurationreport", true, "endpoints.autoconfigurationreport"); + super(Config.class, AutoConfigurationReportEndpoint.class, "/auto", true, + "endpoints.autoconfigurationreport"); } @Configuration @EnableConfigurationProperties - @EnableAutoConfigurationReport public static class Config { + @Bean + public AutoConfigurationReport autoConfigurationReport() { + return new AutoConfigurationReport(); + } + @Bean public AutoConfigurationReportEndpoint endpoint() { return new AutoConfigurationReportEndpoint(); 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 0fdbc5c6c83..82978ff7aae 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 @@ -28,10 +28,12 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.condition.Outcome; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ConditionContext; import org.springframework.context.event.ContextRefreshedEvent; @@ -46,6 +48,8 @@ import org.springframework.context.event.ContextRefreshedEvent; public class AutoConfigurationReport implements ApplicationContextAware, ApplicationListener { + private static final String AUTO_CONFIGURATION_REPORT = "autoConfigurationReport"; + private static Log logger = LogFactory.getLog(AutoConfigurationReport.class); private Set beansCreated = new LinkedHashSet(); @@ -57,13 +61,27 @@ public class AutoConfigurationReport implements ApplicationContextAware, public static void registerDecision(ConditionContext context, String message, String classOrMethodName, Outcome outcome) { - if (context.getBeanFactory().containsBeanDefinition("autoConfigurationReport")) { + if (context.getBeanFactory().containsBeanDefinition(AUTO_CONFIGURATION_REPORT) + || context.getBeanFactory().containsSingleton(AUTO_CONFIGURATION_REPORT)) { AutoConfigurationReport autoconfigurationReport = context.getBeanFactory() .getBean(AutoConfigurationReport.class); autoconfigurationReport.registerDecision(message, classOrMethodName, outcome); } } + public static AutoConfigurationReport registerReport( + ConfigurableApplicationContext applicationContext, + ConfigurableListableBeanFactory beanFactory) { + if (!beanFactory.containsBean(AutoConfigurationReport.AUTO_CONFIGURATION_REPORT)) { + AutoConfigurationReport report = new AutoConfigurationReport(); + report.setApplicationContext(applicationContext); + beanFactory.registerSingleton( + AutoConfigurationReport.AUTO_CONFIGURATION_REPORT, report); + } + return beanFactory.getBean(AutoConfigurationReport.AUTO_CONFIGURATION_REPORT, + AutoConfigurationReport.class); + } + private void registerDecision(String message, String classOrMethodName, Outcome outcome) { AutoConfigurationDecision decision = new AutoConfigurationDecision(message, diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationReportApplicationContextInitializer.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationReportApplicationContextInitializer.java new file mode 100644 index 00000000000..d8a4f8b7148 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/report/AutoConfigurationReportApplicationContextInitializer.java @@ -0,0 +1,48 @@ +/* + * Copyright 2012-2013 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.boot.autoconfigure.report; + +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.SpringApplicationErrorHandler; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; + +/** + * @author Dave Syer + */ +public class AutoConfigurationReportApplicationContextInitializer implements + ApplicationContextInitializer, + SpringApplicationErrorHandler { + + private AutoConfigurationReport report; + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); + this.report = AutoConfigurationReport.registerReport(applicationContext, + beanFactory); + } + + @Override + public void handle(SpringApplication springApplication, String[] args, Throwable e) { + if (this.report != null) { + this.report.initialize(); // salvage a report if possible + } + } + +} diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index e728992ab30..278a0d69283 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -20,3 +20,5 @@ org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\ org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\ org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\ org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration +org.springframework.context.ApplicationContextInitializer=\ +org.springframework.boot.autoconfigure.report.AutoConfigurationReportApplicationContextInitializer diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationReportTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationReportTests.java index 16c0df15301..5f59bc183b8 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationReportTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationReportTests.java @@ -16,9 +16,6 @@ package org.springframework.boot.autoconfigure; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import java.util.List; import java.util.Map; import java.util.Set; @@ -30,8 +27,8 @@ import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration; import org.springframework.boot.autoconfigure.jms.JmsTemplateAutoConfiguration; import org.springframework.boot.autoconfigure.report.AutoConfigurationReport; +import org.springframework.boot.autoconfigure.report.AutoConfigurationReportApplicationContextInitializer; import org.springframework.boot.autoconfigure.report.CreatedBeanInfo; -import org.springframework.boot.autoconfigure.report.EnableAutoConfigurationReport; import org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; @@ -39,9 +36,12 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; import org.springframework.jms.core.JmsTemplate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * Tests for {@link AutoConfigurationReport}. - * + * * @author Greg Turnquist */ public class AutoConfigurationReportTests { @@ -53,6 +53,8 @@ public class AutoConfigurationReportTests { this.context = new AnnotationConfigApplicationContext(); this.context.register(TestConfiguration.class, PropertyPlaceholderAutoConfiguration.class); + new AutoConfigurationReportApplicationContextInitializer() + .initialize(this.context); this.context.refresh(); AutoConfigurationReport autoconfigSettings = this.context .getBean(AutoConfigurationReport.class); @@ -86,7 +88,8 @@ public class AutoConfigurationReportTests { @Test public void rabbitReportTest() { this.context = new AnnotationConfigApplicationContext(); - this.context.register(TestConfiguration.class, RabbitAutoConfiguration.class); + this.context.register(TestConfiguration.class, RabbitAutoConfiguration.class, + AutoConfigurationReport.class); this.context.refresh(); AutoConfigurationReport autoconfigSettings = this.context .getBean(AutoConfigurationReport.class); @@ -117,13 +120,16 @@ public class AutoConfigurationReportTests { totalDecisions += 1; if (decision.contains("RabbitConnectionFactoryCreator matched")) { foundRabbitConnectionFactory = true; - } else if (decision.contains("OnExpressionCondition") + } + else if (decision.contains("OnExpressionCondition") && decision.contains("amqpAdmin matched due to SpEL expression")) { foundAmqpAdminExpressionCondition = true; - } else if (decision.contains("OnBeanCondition") + } + else if (decision.contains("OnBeanCondition") && decision.contains("amqpAdmin matched")) { foundAmqpAdminBeanCondition = true; - } else if (decision.contains("rabbitTemplate matched")) { + } + else if (decision.contains("rabbitTemplate matched")) { foundRabbitTemplateCondition = true; } } @@ -139,7 +145,8 @@ public class AutoConfigurationReportTests { public void verifyItGathersNegativeMatches() { this.context = new AnnotationConfigApplicationContext(); this.context.register(TestConfiguration2.class, - JmsTemplateAutoConfiguration.class, MultipartAutoConfiguration.class); + JmsTemplateAutoConfiguration.class, MultipartAutoConfiguration.class, + AutoConfigurationReport.class); this.context.refresh(); AutoConfigurationReport autoconfigSettings = this.context .getBean(AutoConfigurationReport.class); @@ -156,7 +163,8 @@ public class AutoConfigurationReportTests { .contains("JmsTemplateAutoConfiguration#jmsTemplate did not match") && decision.contains("found the following [myOwnJmsTemplate]")) { foundMyOwnJmsTemplateAndBackedOff = true; - } else if (decision.contains("MultipartAutoConfiguration did not match") + } + else if (decision.contains("MultipartAutoConfiguration did not match") && decision .contains("list['javax.servlet.MultipartConfigElement']") && decision.contains("found no beans")) { @@ -164,7 +172,8 @@ public class AutoConfigurationReportTests { } } } - // varying situations might cause multi-conditional beans to evaluate in different orders + // varying situations might cause multi-conditional beans to evaluate in different + // orders assertTrue(totalNegativeDecisions >= 2); assertTrue(foundMyOwnJmsTemplateAndBackedOff); assertTrue(didNotFindMultipartConfigElement); @@ -172,12 +181,10 @@ public class AutoConfigurationReportTests { } @Configuration - @EnableAutoConfigurationReport public static class TestConfiguration { } @Configuration - @EnableAutoConfigurationReport public static class TestConfiguration2 { @Bean JmsTemplate myOwnJmsTemplate(javax.jms.ConnectionFactory connectionFactory) { diff --git a/spring-boot-samples/spring-boot-sample-secure/src/main/java/org/springframework/boot/sample/ops/ui/SampleSecureApplication.java b/spring-boot-samples/spring-boot-sample-secure/src/main/java/org/springframework/boot/sample/ops/ui/SampleSecureApplication.java index c6817a743b9..672bc5baf1f 100644 --- a/spring-boot-samples/spring-boot-sample-secure/src/main/java/org/springframework/boot/sample/ops/ui/SampleSecureApplication.java +++ b/spring-boot-samples/spring-boot-sample-secure/src/main/java/org/springframework/boot/sample/ops/ui/SampleSecureApplication.java @@ -20,7 +20,6 @@ import java.util.Date; import java.util.Map; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.report.EnableAutoConfigurationReport; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -34,7 +33,6 @@ import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @EnableAutoConfiguration -@EnableAutoConfigurationReport @ComponentScan @Controller public class SampleSecureApplication extends WebMvcConfigurerAdapter {