QUESTION:
If you don't know in advance what folders/JARs you need added to the classpath for every Tomcat webapp, what method can you use with Java 11+ / Tomcat 9+ to load folders/JARs into the classpath so that they will be available in every app?
PREVIOUS / OTHER APPROACHES, for reference:
Java 8 (Tomcat or command line app):
- Get a reference to the classloader.
- Cast it to URLClassLoader (important only for command line app, Tomcat's is already a URLClassLoader).
- Use reflection to call URLClassLoader.addUrl(), to bypass the fact that it is a protected method.
- This was the most common practice for over a decade.
Java 11 Tomcat webapp - dynamically add libraries using the Java 8 method:
- This is still temporarily possible in Java 11 / Tomcat 9.
- But it gives a warning that it is an illegal operation that will be prevented in future Java versions.
Java 11 command line app:
- Not related to Tomcat, including it here for completeness and because the method might be at the core or part of a Tomcat solution. So it is good to at least understand it.
- Extend URLClassLoader, making addUrl() public with super.addUrl().
- Instantiate it with the application/system classloader as its parent.
- Add the JARs and folders.
- Instantiate every class in your app using this classloader. I apologize for not having details for this step. It is the consensus in all forums, but I did not find a best practice for how to instantiate with a custom/child classloader in as thought-free a manner as when you use the default system classloader. It "seems" that you need to explicitly load each class with the custom classloader before instantiating an object. But that is so inconvenient that it can't be the intended approach / best practice. A real and relevant issue, but not the focus of this thread.
Java 11 Tomcat webapp - manual inclusion of JARs/folders:
- Add them to the Tomcat lib folder, or create folders for your libraries and declare them in catalina.properties common classloader list.
- This method works but is not dynamic. Every time you add folders for other libraries you have to manually update catalina.properties.
Java 11 Tomcat webapp - add libraries in WEB-INF/lib:
- This is the default location for libraries in a webapp.
- The library needs to be included in every webapp.
- A tool like Maven can help with each webapp, but it still isn't a truly dynamic approach that can auto-detect libraries at server startup and add them to the classpath.
- If the library contains a configuration file and that configuration changes, it has to be updated on every webapp, or have to rely on manually creating symbolic links for file. Very clunky and prone to human error.
- And of course this is not dynamic, as it can't automatically discover JARs/folders, they have to be explicitly and manually included.
AN IDEA FOR TOMCAT DEVELOPERS:
- If the issue of losing the ability to dynamically add JARs to the Tomcat common classloader has not yet been addressed, maybe the need can be eliminated as follows:
- Currently the common classloader only loads from the folder/jars mentioned under common in catalina.properties, like the tomcat lib folder.
- Expand the behavior so that a folder referenced in catalina.properties common causes the classloader to include the folder, its contained JARs, and any subfolder tree and its JARs.
- So, when we need to dynamically add folders/jars all we'd have to do is create a subfolder (or more) under lib, and place our stuff there.
- For example:
lib
lib/myOpenSourceLibs
lib/myOpenSourceLibs/apache
lib/myOpenSourceLibs/spring
lib/myOpenSourceLibs/dependencies
lib/myOrgLibraries
lib/myOrgLibraries/payrollSystemInterface
lib/myOrgLibraries/generalLedgerSystemInterface