0
votes

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
1

1 Answers

0
votes

If you don't know in advance what folders/JARs you need added to the classpath for every Tomcat webapp => then DON'T add those JARS to the classpath for all apps.

Its easy to modify the startup for Tomcat to auto-scan a specific directory tree of jar files and build a class path - just modify bin\setenv.bat or bin/setenv.sh.

However, deciding which jars you drop into a shared classpath directory for all webapps to use must be a decision based after reviewing every web application dependencies, and then being sure that every single web app is re-built without including any of the jars that has been selected for sharing across all webapps.

It is sensible to have JDBC drivers, connection pooling and other core components for user logins with your apps shared for all webapps, but you will run into issues if you find that one app is using different versions of jars or if you don't want to link the release cycle of webapps that may have been developed by different teams which are deployed to same servers.