Forums Register Login

Unload or Reload a Dymnically Loaded Class

+Pie Number of slices to send: Send
I am building a telephony routing application which includes a digit translation and routing engine. The engine uses a number of rules provisioned in a database to make decisions on how to route (or reject) calls and how calling attributes such as calling-party number, called-party number calling-line-id should be altered before being routed to the next hop. Some decisions are too complex to describe in the database-provisioned rules and/or rely on information outside of the application. To support this, there is a rule type which allows a plug-in to be called to assist in the decision-making and attribute manipulation. The routing application needs to be highly available, so I decided to dynamically load the plug-ins rather than bundle them with the application so that they could be loaded (and unloaded) without the need to stop and start the application.

The class below is responsible for loading the plug-in JARs s from a directory, and making them available to the routing engine when needed. It loads the plug-ins when instantiated, and attempts to reload the set of plug-in when requested.

What I am finding is, that when I try to reload the plug-ins, that the old classes stay loaded and do not get updated. I assumed that if I removed the entries from the registry map, and made sure that there were no references to any plug-in class objects, that the class loader instances would have no more references, and the class loaders would go-away, and that I would be able to load the new versions of the plug-ins.

Working with class loaders is new for me, so any hints or words of wisdom will be appreciated.

+Pie Number of slices to send: Send
From a quick look it seems you're always using the same class loader - that will not work, as you can't load an updated version of a class through the same class loader. Each time you load the jar file(s) you need to instantiate a new class loader instance for that. Even then it will only work if all the classes loaded through the old class loader have been unloaded, and the previously used class loader as well (which can be tricky to make happen). You may want to check out OSGi for this - reloading classes at runtime is one of the main points of using it.
+Pie Number of slices to send: Send
In line #95, my intent is to instantiate a new class loader for each class found in each JAR file. I'll take a look at OSGi .

Thanks.

+Pie Number of slices to send: Send
Ah, I missed that part. But still, the previously used classloader needs to be unloaded first, and I'm not sure there is a definite series of steps one can execute that ensures this will happen.

Be aware that OSGi has a non-trivial learning curve. You may want to use it via a container such as Apache Karaf.
+Pie Number of slices to send: Send
What happens with TranslationPlugins loaded by getPlugin method? You cannot update code of already existing classes that way. All you can do is to create new plugin instances with a new code. But all previous instances would use old code. Moreover, that old instances mark corresponding classes as used and ineligible for Garbage Collection. This in turn marks a classloaders as ineligible for GC. To unload a classloader you should first ensure that there are no instances of classes loaded by that classloader. And some additional flags may be required to allow classes collection, read about CMSClassUnloading. Remember, all that can't reload code of existing class/object. It can only help you to remove unneeded classes and classloaders from memory.

Maybe there is some way to update class files on-the-fly using JVMTI, but I do not recommend this for a production environment.
(1 cow) 1
+Pie Number of slices to send: Send
 

Maxim Karvonen wrote:What happens with TranslationPlugins loaded by getPlugin method?


The instances are used briefly, and then discarded.

I did finally find the issue which was causing the problem. I ignored a warning for line #95 (ClassLoader classLoader = new URLClassLoader(urls, parentClassLoader);), stating: Resource Leak 'classLoader' is never closed. It turns-out this actually needed to be addressed - because the class loader would never unload as long as there was a dangling reference.

Since there is no ClassLoader method to explicitly close it, I changed my class loader object to be an instance of URLClassLoader (which implements AutoCloseable), and used a try-with-resources statement to instantiate the class loader object (try (URLClassLoader classLoader = new URLClassLoader(urls, parentClassLoader)) { ... }), so that it would be automatically closed at the end of the block. It worked!

My next step is to clean-up what I have done, and add a directory watcher thread to automatically register and de-register plug-ins as they are added/removed/replaced.

Ron
+Pie Number of slices to send: Send
Hi, Ron.

Thank you for sharing your solution! I never noticed that close method before.
You don't like waffles? Well, do you like this tiny ad?
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com


reply
reply
This thread has been viewed 19900 times.
Similar Threads
Running JUnit tests from class file in another jar
Getting classes in a package
dynamically loading a class file from a jar file
Can some one help me out with this code..
dont know where the problem is... after loading... please help me out....
More...

All times above are in ranch (not your local) time.
The current ranch time is
Mar 28, 2024 11:25:06.