-
Notifications
You must be signed in to change notification settings - Fork 41.5k
Description
Simple Scenario: Spring Boot 2.0.0.RC1 Application with Spring-Cloud Config is built as WAR-File and deployed into a Tomcat 8.5. Trying to refresh the context using the JMX Refresh endpoint results in an Exception:
java.lang.IllegalStateException: Cannot load configuration class: org.springframework.cloud.context.refresh.ContextRefresher$Empty
at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:416) ~[spring-context-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanFactory(ConfigurationClassPostProcessor.java:254) ~[spring-context-5.0.3.RELEASE.jar:5.0.3.RELEASE]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:284) ~[spring-context-5.0.3.RELEASE.jar:2.5.5]
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:128) ~[spring-context-5.0.3.RELEASE.jar:2.5.5]
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:693) ~[spring-context-5.0.3.RELEASE.jar:2.5.5]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:531) ~[spring-context-5.0.3.RELEASE.jar:2.5.5]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) ~[spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388) ~[spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327) ~[spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:136) [spring-boot-2.0.0.RC1.jar:2.0.0.RC1]
at org.springframework.cloud.context.refresh.ContextRefresher.addConfigFilesToEnvironment(ContextRefresher.java:82) [spring-cloud-context-2.0.0.M5.jar:2.0.0.M5]
at org.springframework.cloud.context.refresh.ContextRefresher.refresh(ContextRefresher.java:61) [spring-cloud-context-2.0.0.M5.jar:2.0.0.M5]
at org.springframework.cloud.endpoint.RefreshEndpoint.refresh(RefreshEndpoint.java:41) [spring-cloud-context-2.0.0.M5.jar:2.0.0.M5]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:223) [spring-core-5.0.3.RELEASE.jar:2.5.5]
at org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker.invoke(ReflectiveOperationInvoker.java:74) [spring-boot-actuator-2.0.0.RC1.jar:2.0.0.RC1]
at org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation.invoke(AbstractDiscoveredOperation.java:62) [spring-boot-actuator-2.0.0.RC1.jar:2.0.0.RC1]
at org.springframework.boot.actuate.endpoint.jmx.EndpointMBean.invoke(EndpointMBean.java:99) [spring-boot-actuator-2.0.0.RC1.jar:2.0.0.RC1]
at org.springframework.boot.actuate.endpoint.jmx.EndpointMBean.invoke(EndpointMBean.java:91) [spring-boot-actuator-2.0.0.RC1.jar:2.0.0.RC1]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) [na:1.8.0_131]
at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) [na:1.8.0_131]
at com.sun.jmx.remote.security.MBeanServerAccessController.invoke(MBeanServerAccessController.java:468) [na:1.8.0_131]
at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468) [na:1.8.0_131]
at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76) [na:1.8.0_131]
at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309) [na:1.8.0_131]
at java.security.AccessController.doPrivileged(Native Method) [na:1.8.0_131]
at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1408) [na:1.8.0_131]
at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829) [na:1.8.0_131]
at sun.reflect.GeneratedMethodAccessor934.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:346) [na:1.8.0_131]
at sun.rmi.transport.Transport$1.run(Transport.java:200) [na:1.8.0_131]
at sun.rmi.transport.Transport$1.run(Transport.java:197) [na:1.8.0_131]
at java.security.AccessController.doPrivileged(Native Method) [na:1.8.0_131]
at sun.rmi.transport.Transport.serviceCall(Transport.java:196) [na:1.8.0_131]
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568) [na:1.8.0_131]
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826) [na:1.8.0_131]
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683) [na:1.8.0_131]
at java.security.AccessController.doPrivileged(Native Method) [na:1.8.0_131]
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682) [na:1.8.0_131]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_131]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_131]
at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_131]
Caused by: java.lang.ClassNotFoundException: org.springframework.cloud.context.refresh.ContextRefresher$Empty
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_131]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_131]
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_131]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_131]
at org.springframework.util.ClassUtils.forName(ClassUtils.java:264) ~[spring-core-5.0.3.RELEASE.jar:2.5.5]
at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:437) ~[spring-beans-5.0.3.RELEASE.jar:2.5.5]
at org.springframework.context.annotation.ConfigurationClassPostProcessor.enhanceConfigurationClasses(ConfigurationClassPostProcessor.java:403) ~[spring-context-5.0.3.RELEASE.jar:5.0.3.RELEASE]
... 46 common frames omitted
After some digging it turns out the ConfigurationClassPostProcessor
gets the Class Loader injected which resolves to sun.misc.Launcher$AppClassLoader
instead of the one used to start the application -ParallelWebappClassLoader
.
To resolve the class loader
org.springframework.util.ClassUtils#getDefaultClassLoader
is used, which resolves the class loader using Thread.currentThread().getContextClassLoader()
, now we are still within the JMX Thread -> You get the wrong class loader.
When starting with an embedded Tomcat this problem does not happen because the Application uses the same class loader when starting as during the JMX call (always sun.misc.Launcher$AppClassLoader
)