From 6c8f8c9d827a5340f9e6493c14d8c252d1f0d52a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 21 Jun 2016 15:03:10 +0100 Subject: [PATCH] Better diagnotics when ESCF subclass breaks with custom management port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a custom management.port is used, the child context is configured with an EmbeddedServletContainerFactory bean that has the same class as the parent context’s EmbeddedServletContainerFactory bean. This ensures that the child context uses the same type of embedded container as its parent when there are multiple embedded containers on the classpath. It also causes a failure when the custom EmbeddedServletContainerFactory subclass cannot be instantiated, for example because it’s an anonymous inner-class. This commit improves the diagnostics so that we fail fast with an information exception message when we detect that the embedded servlet container factory bean’s class cannot be instantiated. Closes gh-6193 --- .../EndpointWebMvcAutoConfiguration.java | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java index 66b72769f77..bc96a6917d9 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.autoconfigure; import java.io.IOException; +import java.lang.reflect.Modifier; import javax.servlet.FilterChain; import javax.servlet.Servlet; @@ -28,6 +29,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; +import org.springframework.beans.FatalBeanException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -188,13 +190,12 @@ public class EndpointWebMvcAutoConfiguration private void registerEmbeddedServletContainerFactory( AnnotationConfigEmbeddedWebApplicationContext childContext) { try { - EmbeddedServletContainerFactory servletContainerFactory = this.applicationContext - .getBean(EmbeddedServletContainerFactory.class); ConfigurableListableBeanFactory beanFactory = childContext.getBeanFactory(); if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; registry.registerBeanDefinition("embeddedServletContainerFactory", - new RootBeanDefinition(servletContainerFactory.getClass())); + new RootBeanDefinition( + determineEmbeddedServletContainerFactoryClass())); } } catch (NoSuchBeanDefinitionException ex) { @@ -202,6 +203,25 @@ public class EndpointWebMvcAutoConfiguration } } + private Class determineEmbeddedServletContainerFactoryClass() + throws NoSuchBeanDefinitionException { + Class servletContainerFactoryClass = this.applicationContext + .getBean(EmbeddedServletContainerFactory.class).getClass(); + if (cannotBeInstantiated(servletContainerFactoryClass)) { + throw new FatalBeanException("EmbeddedServletContainerFactory implementation " + + servletContainerFactoryClass.getName() + " cannot be instantiated. " + + "To allow a separate management port to be used, a top-level class " + + "or static inner class should be used instead"); + } + return servletContainerFactoryClass; + } + + private boolean cannotBeInstantiated(Class clazz) { + return clazz.isLocalClass() + || (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) + || clazz.isAnonymousClass(); + } + /** * Add an alias for 'local.management.port' that actually resolves using * 'local.server.port'.