Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-14932

Class loading issues due to thread context classloader hierarchy (Spring Web Reactive + Tomcat)





      This is the scenario:

      • A web application uses a library.
      • That library needs to dynamically load a class that implements a specific interface, for example, in order to select the best implementation for the specific environment in which it is being run.

      Observed Result

      When using Spring Web Reactive in a Spring Boot 2.0.0 (snapshot) application, if Tomcat is used as a server, a ClassNotFound exception is thrown when the library tries to load the implementation class by means of the thread context class loader.

      Example application

      Example application: https://github.com/danielfernandez/test-spring-boot-tomcat

      The above application replicates the scenario with Spring Boot 1.4.2 and 2.0.0, using Spring Web MVC and Spring Web Reactive (in 2.0.0). Spring Web Reactive is tested both using Netty and Tomcat. Only Tomcat fails.

      Possible Diagnosis

      This is possibly due to the hierarchy of the thread context class loader. Let's compare:

      Thread context class loader in Spring Boot 2.0.0, Spring Web MVC 5.0.0, Tomcat:

      +-> sun.misc.Launcher$ExtClassLoader - [sun.misc.Launcher$ExtClassLoader@198ff037]
          +-> sun.misc.Launcher$AppClassLoader - [sun.misc.Launcher$AppClassLoader@330bedb4]
              +-> org.springframework.boot.loader.LaunchedURLClassLoader - [org.springframework.boot.loader.LaunchedURLClassLoader@65ab7765]
                  +-> org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedWebappClassLoader - [TomcatEmbeddedWebappClassLoader\n\n  context: ROOT\n\n  delegate: true\n\n----------> Parent Classloader:\n\norg.springframework.boot.loader.LaunchedURLClassLoader@65ab7765\n\n]

      Thread context class loader in Spring Boot 2.0.0, Spring Web Reactive 5.0.0, Netty:

      +-> sun.misc.Launcher$ExtClassLoader - [sun.misc.Launcher$ExtClassLoader@67449f2]
          +-> sun.misc.Launcher$AppClassLoader - [sun.misc.Launcher$AppClassLoader@330bedb4]
              +-> org.springframework.boot.loader.LaunchedURLClassLoader - [org.springframework.boot.loader.LaunchedURLClassLoader@65ab7765]

      Thread context class loader in Spring Boot 2.0.0, Spring Web Reactive 5.0.0, Tomcat:

      +-> sun.misc.Launcher$ExtClassLoader - [sun.misc.Launcher$ExtClassLoader@32e33c96]
          +-> sun.misc.Launcher$AppClassLoader - [sun.misc.Launcher$AppClassLoader@330bedb4]
              +-> org.apache.catalina.loader.ParallelWebappClassLoader - [ParallelWebappClassLoader\n\n  context: ROOT\n\n  delegate: false\n\n----------> Parent Classloader:\n\nsun.misc.Launcher$AppClassLoader@330bedb4\n\n]

      Given the org.springframework.boot.loader.LaunchedURLClassLoader is the one which class path contains all the .jar files contained inside the Spring Boot ├╝ber jar, it seems as if the org.apache.catalina.loader.ParallelWebappClassLoader used as a thread context class loader in Spring Web Reactive + Tomcat should be delegating to LaunchedURLClassLoader. But it isn't.

      Please see the README for the example application on GitHub for more detail on how this was tested and diagnosed.


      This affects the integration of Thymeleaf into applications using Spring Web Reactive. Thymeleaf needs to initialise some implementations depending on the specific scenario it is being run on, and this issue makes it impossible to use the current version of the Thymeleaf + Spring integration packages in Spring Web Reactive applications using Tomcat.




            bclozel Brian Clozel
            dfernandez Daniel Fernández
            Last updater:
            Spring Issuemaster
            0 Vote for this issue
            2 Start watching this issue


              Days since last comment:
              1 year, 37 weeks ago