ReflectUtil.loadClass() and custom classloader
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-17-2011 10:11 AM
public static Class<?> loadClass(String className) { Class<?> clazz = null; ClassLoader classLoader = getCustomClassLoader(); // First exception in chain of classloaders will be used as cause when no class is found in any of them Throwable throwable = null; if(classLoader != null) { try { LOG.finest("Trying to load class with custom classloader: " + className); clazz = Class.forName(className, true, classLoader); } catch(Throwable t) { throwable = t; } }…
Is there any particular reason to load class using custom classloader in this way:
clazz = Class.forName(className, true, classLoader);
instead of directly calling classloader method:clazz = classLoader.loadClass(className);
?My goal is to have possibility to load two versions of the same class during runtime depending on deployment's id during runtime.
It seems that call with Class.forName() my classloader is not called but some cached class is loaded which is not what I (and probably other custom classloader developers) want to achieve.
- Labels:
-
Archive
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-21-2011 04:51 AM
Class.forName() does what you want but activiti caches instances of JavaDelegate in the DeploymentCache.
This hurts you if you deploy a process and then redeploy your classes without creating a new process engine deployment. Then the DeploymentCache will continue to hold on to your "old" class definition.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-22-2011 05:45 AM
I've written my own BarDeployer on top of com.camunda.fox.activiti.enterprise.deployer.ActivitiDeployerJboss5. For each BAR deployment it creates a BarClassloader(also written by myself) which caches and loads classes from BAR resource file. I can see two possibilities here: I can manage handling class caching with DeploymentCache or give up DeploymentCache and do it all by myself. But to do it I would have to know how is it done in engine.
I've debbuged DeploymentCache uses during deployment of Bar file and all that is done there is that the process definition is added to the cache.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-23-2011 09:34 AM
clazz = classLoader.loadClass(className);
the method loadClass of my classLoader is called every time loadClass in ReflectUtil was called - which is the way I want to achievebut with original
clazz = Class.forName(className, true, classLoader);
it is done only for the first time the class is loadedSo maybe I have to change my question to: What I have to do to be sure that my classloader is called every time some activiti engine class calls ReflectUtil.loadClass?
From my point of view, possibility of specifying custom classloader in the enginge is a great idea, but it gives a user almost no flexibility with dynamic loading different versions of the same class.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-28-2011 01:11 AM
1) On the deployment cache:
Instances of JavaDelegate/ActivityBehavior referenced by a process are loaded by activiti at process execution time. (See for instance org.activiti.engine.impl.bpmn.helper.ClassDelegate.activityBehaviorInstance).
However, as activiti maintains a cache of process definitions (the org.activiti.engine.impl.persistence.deploy.DeploymentCache), process definitions will continue to reference an ActivityBehavior instance for the lifetime of the process engine (the cache does not support eviction).
This means that:
- after an instance of the delegate is loaded for the first time the process engine continues referencing that instance through the DeploymentCache
- instances of JavaDelegate are shared between all process instances in the same process engine
- you will see inconsistent behavior if you use custom classloaders and the the deployment lifecycle of your classes is not in sync with your processes (i.e. if you redeploy your classes without creating a new process definition, activiti will continue referencing the "old" classes. If you "restart" the engine, it will load the "new" classes.)
- also in combination with a custom classloader: activiti will continue to hold on to any classes loaded by the process definition: even if you "undeploy" these classes through some other mechanism (ie. if you load classes fro man osgi bundle and undeploy that bundle, activiti will still reference them)
- deactivate the deployment cache (implement a subclass which does not cache anything)
- use proxy delegates (a delegate which loads the "actual" delegate)
- do not use java delegates (but lookup objects the lifecycle of which is managed by some other container like EJB/CDI, OSGi, Spring, … )
2) On Class.forName(name, initialize, classloader) vs. Classloader.loadClass(name)
You have to garbage collect the classloader that loaded a class / create a new instance of your classloader. If you don't, the JVM will not attempt to reload the class. Th JVM will ask the same classloader only once for the same class. Maybe that is the behavior you see.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
11-28-2011 06:04 AM
thanks for the comprehensive reply.
At the end of the last week I had an idea to override ProcessEngineConfigurationImpl.getClassLoader() in the manner that it returns deployment-based classloader (deploymentId is obtained from the ExecutionContext; if there's no classloader for specified deployment or there's no execution context, some default classloader is returned) and it seems that in my simple test cases for all of the processes proper version of classes are loaded.
Do you see any possible drawbacks in doing it this way?
(Actually I have to think it over as well


- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-13-2014 03:33 AM
Method forName caches classes (see http://blog.bjhargrave.com/2007/09/classforname-caches-defined-class-in.html) internally in native implementation for no understandable reason.
This blocks implementing per-deployment class loading with a single dispatcher class loader set to activiti configuration, which detects deployment context and delegates to a per-deployment class loader.
Could anyone explain why ReflectUtil shouldn't use ClassLoader.loadClass instead of Class.forName?
To anyone who is trying to implement per-deployment class loading: the workaround is to override <java>org.activiti.engine.ProcessEngineConfiguration.getClassLoader()</java> method and return your per-deployment class loader (you can detect deployment context via <java>org.activiti.engine.impl.context.Context.getExecutionContext().getProcessDefinition().getDeploymentId()</java>).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-19-2014 05:28 AM

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-19-2014 10:36 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-20-2014 02:46 PM
Do you reckon it is simply a matter of changing the implementation? I'm kind of nervous cause the OSGO bits are always hard (and hard to test!) and I definitely don't want to go break them.
