ApplicationContextInitializers now listen for ContextRefreshedEvent
The AutoConfigurationReportLoggingInitializer wasn't working in non-GenericApplicationContext becasue teh BeanFatcory wasn't available for registering its listener during initialization. Instead of relying on that rather fragile state I decided to give any ApplicationContextInitializer that was itself an ApplicationListener an explicit callback with a ContextRefreshedEvent, and move that interface up a level in the logging initializer. Works much better.
This commit is contained in:
@@ -20,7 +20,6 @@ import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringApplicationErrorHandler;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationReport.ConditionAndOutcome;
|
||||
@@ -30,6 +29,7 @@ import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -49,18 +49,21 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class AutoConfigurationReportLoggingInitializer implements
|
||||
ApplicationContextInitializer<ConfigurableApplicationContext>,
|
||||
SpringApplicationErrorHandler {
|
||||
SpringApplicationErrorHandler, ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
private static final String LOGGER_BEAN = "autoConfigurationReportLogger";
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private AutoConfigurationReportLogger loggerBean;
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
private AutoConfigurationReport report;
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
this.loggerBean = new AutoConfigurationReportLogger(applicationContext);
|
||||
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
|
||||
if (!beanFactory.containsSingleton(LOGGER_BEAN)) {
|
||||
beanFactory.registerSingleton(LOGGER_BEAN, this.loggerBean);
|
||||
this.applicationContext = applicationContext;
|
||||
if (applicationContext instanceof GenericApplicationContext) {
|
||||
// Get the report early in case the context fails to load
|
||||
this.report = AutoConfigurationReport.get(this.applicationContext
|
||||
.getBeanFactory());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,99 +71,80 @@ public class AutoConfigurationReportLoggingInitializer implements
|
||||
public void handleError(SpringApplication application,
|
||||
ConfigurableApplicationContext applicationContext, String[] args,
|
||||
Throwable exception) {
|
||||
if (this.loggerBean != null) {
|
||||
this.loggerBean.logAutoConfigurationReport(true);
|
||||
logAutoConfigurationReport(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
if (event.getApplicationContext() == this.applicationContext) {
|
||||
logAutoConfigurationReport();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Spring bean to actually perform the logging.
|
||||
*/
|
||||
public static class AutoConfigurationReportLogger implements
|
||||
ApplicationListener<ContextRefreshedEvent> {
|
||||
private void logAutoConfigurationReport() {
|
||||
logAutoConfigurationReport(!this.applicationContext.isActive());
|
||||
}
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final ConfigurableApplicationContext applicationContext;
|
||||
|
||||
private final AutoConfigurationReport report;
|
||||
|
||||
public AutoConfigurationReportLogger(
|
||||
ConfigurableApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
// Get the report early in case the context fails to load
|
||||
void logAutoConfigurationReport(boolean isCrashReport) {
|
||||
if (this.report == null) {
|
||||
this.report = AutoConfigurationReport.get(this.applicationContext
|
||||
.getBeanFactory());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
if (event.getApplicationContext() == this.applicationContext) {
|
||||
logAutoConfigurationReport();
|
||||
if (this.report.getConditionAndOutcomesBySource().size() > 0) {
|
||||
if (isCrashReport && this.logger.isInfoEnabled()) {
|
||||
this.logger.info(getLogMessage(this.report
|
||||
.getConditionAndOutcomesBySource()));
|
||||
}
|
||||
else if (!isCrashReport && this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(getLogMessage(this.report
|
||||
.getConditionAndOutcomesBySource()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void logAutoConfigurationReport() {
|
||||
logAutoConfigurationReport(!this.applicationContext.isActive());
|
||||
}
|
||||
|
||||
void logAutoConfigurationReport(boolean isCrashReport) {
|
||||
if (this.report.getConditionAndOutcomesBySource().size() > 0) {
|
||||
if (isCrashReport && this.logger.isInfoEnabled()) {
|
||||
this.logger.info(getLogMessage(this.report
|
||||
.getConditionAndOutcomesBySource()));
|
||||
}
|
||||
else if (!isCrashReport && this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(getLogMessage(this.report
|
||||
.getConditionAndOutcomesBySource()));
|
||||
}
|
||||
private StringBuilder getLogMessage(Map<String, ConditionAndOutcomes> outcomes) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append("\n\n\n");
|
||||
message.append("=========================\n");
|
||||
message.append("AUTO-CONFIGURATION REPORT\n");
|
||||
message.append("=========================\n\n\n");
|
||||
message.append("Positive matches:\n");
|
||||
message.append("-----------------\n");
|
||||
for (Map.Entry<String, ConditionAndOutcomes> entry : outcomes.entrySet()) {
|
||||
if (entry.getValue().isFullMatch()) {
|
||||
addLogMessage(message, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private StringBuilder getLogMessage(Map<String, ConditionAndOutcomes> outcomes) {
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append("\n\n\n");
|
||||
message.append("=========================\n");
|
||||
message.append("AUTO-CONFIGURATION REPORT\n");
|
||||
message.append("=========================\n\n\n");
|
||||
message.append("Positive matches:\n");
|
||||
message.append("-----------------\n");
|
||||
for (Map.Entry<String, ConditionAndOutcomes> entry : outcomes.entrySet()) {
|
||||
if (entry.getValue().isFullMatch()) {
|
||||
addLogMessage(message, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
message.append("\n\n");
|
||||
message.append("Negative matches:\n");
|
||||
message.append("-----------------\n");
|
||||
for (Map.Entry<String, ConditionAndOutcomes> entry : outcomes.entrySet()) {
|
||||
if (!entry.getValue().isFullMatch()) {
|
||||
addLogMessage(message, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
message.append("\n\n");
|
||||
return message;
|
||||
}
|
||||
|
||||
private void addLogMessage(StringBuilder message, String source,
|
||||
ConditionAndOutcomes conditionAndOutcomes) {
|
||||
message.append("\n " + ClassUtils.getShortName(source) + "\n");
|
||||
for (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) {
|
||||
message.append(" - ");
|
||||
if (StringUtils.hasLength(conditionAndOutcome.getOutcome().getMessage())) {
|
||||
message.append(conditionAndOutcome.getOutcome().getMessage());
|
||||
}
|
||||
else {
|
||||
message.append(conditionAndOutcome.getOutcome().isMatch() ? "matched"
|
||||
: "did not match");
|
||||
}
|
||||
message.append(" (");
|
||||
message.append(ClassUtils.getShortName(conditionAndOutcome.getCondition()
|
||||
.getClass()));
|
||||
message.append(")\n");
|
||||
message.append("\n\n");
|
||||
message.append("Negative matches:\n");
|
||||
message.append("-----------------\n");
|
||||
for (Map.Entry<String, ConditionAndOutcomes> entry : outcomes.entrySet()) {
|
||||
if (!entry.getValue().isFullMatch()) {
|
||||
addLogMessage(message, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
message.append("\n\n");
|
||||
return message;
|
||||
}
|
||||
|
||||
private void addLogMessage(StringBuilder message, String source,
|
||||
ConditionAndOutcomes conditionAndOutcomes) {
|
||||
message.append("\n " + ClassUtils.getShortName(source) + "\n");
|
||||
for (ConditionAndOutcome conditionAndOutcome : conditionAndOutcomes) {
|
||||
message.append(" - ");
|
||||
if (StringUtils.hasLength(conditionAndOutcome.getOutcome().getMessage())) {
|
||||
message.append(conditionAndOutcome.getOutcome().getMessage());
|
||||
}
|
||||
else {
|
||||
message.append(conditionAndOutcome.getOutcome().isMatch() ? "matched"
|
||||
: "did not match");
|
||||
}
|
||||
message.append(" (");
|
||||
message.append(ClassUtils.getShortName(conditionAndOutcome.getCondition()
|
||||
.getClass()));
|
||||
message.append(")\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,16 +29,19 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurationReportLoggingInitializer.AutoConfigurationReportLogger;
|
||||
import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -104,6 +107,7 @@ public class AutoConfigurationReportLoggingInitializerTests {
|
||||
this.initializer.initialize(context);
|
||||
context.register(Config.class);
|
||||
context.refresh();
|
||||
this.initializer.onApplicationEvent(new ContextRefreshedEvent(context));
|
||||
assertThat(this.debugLog.size(), not(equalTo(0)));
|
||||
}
|
||||
|
||||
@@ -130,6 +134,7 @@ public class AutoConfigurationReportLoggingInitializerTests {
|
||||
this.initializer.initialize(context);
|
||||
context.register(Config.class);
|
||||
context.refresh();
|
||||
this.initializer.onApplicationEvent(new ContextRefreshedEvent(context));
|
||||
for (String message : this.debugLog) {
|
||||
System.out.println(message);
|
||||
}
|
||||
@@ -138,10 +143,29 @@ public class AutoConfigurationReportLoggingInitializerTests {
|
||||
assertThat(l, containsString("not a web application (OnWebApplicationCondition)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canBeUsedInApplicationContext() throws Exception {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(Config.class);
|
||||
new AutoConfigurationReportLoggingInitializer().initialize(context);
|
||||
context.refresh();
|
||||
assertNotNull(context.getBean(AutoConfigurationReport.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canBeUsedInNonGenericApplicationContext() throws Exception {
|
||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
context.setServletContext(new MockServletContext());
|
||||
context.register(Config.class);
|
||||
new AutoConfigurationReportLoggingInitializer().initialize(context);
|
||||
context.refresh();
|
||||
assertNotNull(context.getBean(AutoConfigurationReport.class));
|
||||
}
|
||||
|
||||
public static class MockLogFactory extends LogFactoryImpl {
|
||||
@Override
|
||||
public Log getInstance(String name) throws LogConfigurationException {
|
||||
if (AutoConfigurationReportLogger.class.getName().equals(name)) {
|
||||
if (AutoConfigurationReportLoggingInitializer.class.getName().equals(name)) {
|
||||
return logThreadLocal.get();
|
||||
}
|
||||
return new NoOpLog();
|
||||
|
||||
Reference in New Issue
Block a user