diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java index 13f22f0cc9..68ef12952c 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/SpringApplication.java @@ -312,7 +312,6 @@ public class SpringApplication { stopWatch.start(); DefaultBootstrapContext bootstrapContext = createBootstrapContext(); ConfigurableApplicationContext context = null; - Collection exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(bootstrapContext, this.mainApplicationClass); @@ -323,8 +322,6 @@ public class SpringApplication { Banner printedBanner = printBanner(environment); context = createApplicationContext(); context.setApplicationStartup(this.applicationStartup); - exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, - new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); afterRefresh(context, applicationArguments); @@ -336,7 +333,7 @@ public class SpringApplication { callRunners(context, applicationArguments); } catch (Throwable ex) { - handleRunFailure(context, ex, exceptionReporters, listeners); + handleRunFailure(context, ex, listeners); throw new IllegalStateException(ex); } @@ -344,7 +341,7 @@ public class SpringApplication { listeners.running(context); } catch (Throwable ex) { - handleRunFailure(context, ex, exceptionReporters, null); + handleRunFailure(context, ex, null); throw new IllegalStateException(ex); } return context; @@ -812,7 +809,7 @@ public class SpringApplication { } private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception, - Collection exceptionReporters, SpringApplicationRunListeners listeners) { + SpringApplicationRunListeners listeners) { try { try { handleExitCode(context, exception); @@ -821,7 +818,7 @@ public class SpringApplication { } } finally { - reportFailure(exceptionReporters, exception); + reportFailure(getExceptionReporters(context), exception); if (context != null) { context.close(); } @@ -833,6 +830,16 @@ public class SpringApplication { ReflectionUtils.rethrowRuntimeException(exception); } + private Collection getExceptionReporters(ConfigurableApplicationContext context) { + try { + return getSpringFactoriesInstances(SpringBootExceptionReporter.class, + new Class[] { ConfigurableApplicationContext.class }, context); + } + catch (Throwable ex) { + return Collections.emptyList(); + } + } + private void reportFailure(Collection exceptionReporters, Throwable failure) { try { for (SpringBootExceptionReporter reporter : exceptionReporters) { diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/FailureAnalyzers.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/FailureAnalyzers.java index 86932077fa..191c851dda 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/FailureAnalyzers.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/diagnostics/FailureAnalyzers.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -31,7 +31,6 @@ import org.springframework.context.EnvironmentAware; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.core.log.LogMessage; -import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -61,42 +60,50 @@ final class FailureAnalyzers implements SpringBootExceptionReporter { } FailureAnalyzers(ConfigurableApplicationContext context, ClassLoader classLoader) { - Assert.notNull(context, "Context must not be null"); - this.classLoader = (classLoader != null) ? classLoader : context.getClassLoader(); - this.analyzers = loadFailureAnalyzers(this.classLoader); - prepareFailureAnalyzers(this.analyzers, context); + this.classLoader = (classLoader != null) ? classLoader : getClassLoader(context); + this.analyzers = loadFailureAnalyzers(context, this.classLoader); } - private List loadFailureAnalyzers(ClassLoader classLoader) { - List analyzerNames = SpringFactoriesLoader.loadFactoryNames(FailureAnalyzer.class, classLoader); + private ClassLoader getClassLoader(ConfigurableApplicationContext context) { + return (context != null) ? context.getClassLoader() : null; + } + + private List loadFailureAnalyzers(ConfigurableApplicationContext context, + ClassLoader classLoader) { + List classNames = SpringFactoriesLoader.loadFactoryNames(FailureAnalyzer.class, classLoader); List analyzers = new ArrayList<>(); - for (String analyzerName : analyzerNames) { + for (String className : classNames) { try { - Constructor constructor = ClassUtils.forName(analyzerName, classLoader).getDeclaredConstructor(); - ReflectionUtils.makeAccessible(constructor); - analyzers.add((FailureAnalyzer) constructor.newInstance()); + FailureAnalyzer analyzer = createAnalyzer(context, className); + if (analyzer != null) { + analyzers.add(analyzer); + } } catch (Throwable ex) { - logger.trace(LogMessage.format("Failed to load %s", analyzerName), ex); + logger.trace(LogMessage.format("Failed to load %s", className), ex); } } AnnotationAwareOrderComparator.sort(analyzers); return analyzers; } - private void prepareFailureAnalyzers(List analyzers, ConfigurableApplicationContext context) { - for (FailureAnalyzer analyzer : analyzers) { - prepareAnalyzer(context, analyzer); - } - } - - private void prepareAnalyzer(ConfigurableApplicationContext context, FailureAnalyzer analyzer) { - if (analyzer instanceof BeanFactoryAware) { - ((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory()); - } - if (analyzer instanceof EnvironmentAware) { - ((EnvironmentAware) analyzer).setEnvironment(context.getEnvironment()); + private FailureAnalyzer createAnalyzer(ConfigurableApplicationContext context, String className) throws Exception { + Constructor constructor = ClassUtils.forName(className, this.classLoader).getDeclaredConstructor(); + ReflectionUtils.makeAccessible(constructor); + FailureAnalyzer analyzer = (FailureAnalyzer) constructor.newInstance(); + if (analyzer instanceof BeanFactoryAware || analyzer instanceof EnvironmentAware) { + if (context == null) { + logger.trace(LogMessage.format("Skipping %s due to missing context", className)); + return null; + } + if (analyzer instanceof BeanFactoryAware) { + ((BeanFactoryAware) analyzer).setBeanFactory(context.getBeanFactory()); + } + if (analyzer instanceof EnvironmentAware) { + ((EnvironmentAware) analyzer).setEnvironment(context.getEnvironment()); + } } + return analyzer; } @Override diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersTests.java index d421d02196..a67eed3cfd 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/diagnostics/FailureAnalyzersTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -85,8 +85,19 @@ class FailureAnalyzersTests { verify(failureAnalyzer, times(1)).analyze(failure); } + @Test + void createWithNullContextSkipsAwareAnalyzers() { + RuntimeException failure = new RuntimeException(); + analyzeAndReport("basic.factories", failure, null); + verify(failureAnalyzer, times(1)).analyze(failure); + } + private void analyzeAndReport(String factoriesName, Throwable failure) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + analyzeAndReport(factoriesName, failure, context); + } + + private void analyzeAndReport(String factoriesName, Throwable failure, AnnotationConfigApplicationContext context) { ClassLoader classLoader = new CustomSpringFactoriesClassLoader(factoriesName); new FailureAnalyzers(context, classLoader).reportException(failure); }