I happily used DBCP and DBCP2 with Spring for over a decade. I am now trying
to migrate from Java 8 to Java 11 and hit a terrible snag, described below:
* My apps dynamically load the classpath from a tree of folder that
contains many JARs. Yes, I can change this model in the future but for now I
need to migrate many apps quickly and that means keeping this design.
* The old techniques to do the above broke starting in Java 9, so I must
now use a custom classloader. That was easy to write, and I set it with
thread.setContextClassLoader(myClassloader). From that point on in "vanilla"
Java my apps find the classes fine as all the needed libraries are in the
classpath.
* But I define my DBCP2 DataSource in a Spring context.xml file. This
is where things break.
o I get a ClassNotFoundException for org.apache.commons.pool2.ObjectPool when
loaded indirectly by the Spring bean specified with
class="org.apache.commons.dbcp2.BasicDataSource".
o Curiously, I can successfully load the class manually with
myClassloader.loadClass("org.apache.commons.pool2.ObjectPool") in my code just
fine, confirming that it is properly on the classloader's classpath.
* My conclusion (maybe erroneous) is that Spring is reverting to the
system classloader instead of using myClassloader when loading classes, because
at the time of execution (and exception) the commons-pool2 JAR is only known to
myClassloader, not the system classloader.
I suspect that the core of this problem is more about Java 11 or even Spring
than DBCP2. But as most applications that rely on DBCP2 do it through Spring,
a lot of us are migrating out of Java 8, and this issue cripples those
DBCP2-reliant applications... I am hoping that there is a well-known solution
and someone here will be kind enough to share it.
Thank you in advance.