Overview of ClassLoading Issues
Why another page on classloading? Because sometimes when something is explained in a different way with different emphasis it is exactly what somebody needs for their problem.
THIS PAGE IS INTENDED TO BE A CHECKLIST OF COMMON PROBLEMS WITH SOLUTIONS REFERENCED ELSEWHERE
PROBLEMS
I get ClassNotFoundException
This means that some dynamic classloading, i.e. classloader.loadClass() cannot find the class. This FAQ deals with the problem.
I get NoClassDefFoundError
This means that some JVM initiated classloading failed. Usually because of an import on an another class that was in the process of being loaded. Again this FAQ deals with the problem.
I get ClassCastException
There are some places where it reports this when it really means ClassNotFoundException, e.g. the CORBA
PortableRemoteObject.narrow()
Assuming it is the same class name, this problem relates to classes getting loaded from different
classloaders. At compile time your class has only one identity, its name. If you "deploy" a class many times in different jars, it has multiple identities. They are not the same. See below for more information on the solutions to this problem.
This can also be caused by you only redeploying part of your application. e.g. a webapp uses an EJB
and you only redeploy the EJB. The webapp will still have the old versions of the classes.
I get LinkageError
Assuming you are running the version of the class you compiled over, this is a subtle form of ClassCastException when classes are passed between classloaders without doing a cast. e.g. you have a class in two separate deployments and you invoke a method that passes an object from one to the other but using an interface that the class implements. (See chapter 2 of the admin docs for more information of this subtle problem).
I get ClassCircularityError
Assuming this isn't a real circular reference, this is caused by a JDK bug. The solution is to avoid concurrent classloading for this class and probably related classes
ISSUES AND DEFINITIONS
What are the types of things you want to do with classloading?
Sharing and isolation
Sharing
The most common thing to do is to share classes. i.e. choose one version of the classes, test it and let everybody use it. This is usually the easiest to manage, understand and it is certainly the most efficient in terms of resources. It also directly mirrors your build environment.
Isolate
You don't want to share your classes with others but you do want to share common classes and use application server provided classes.
JavaSE Spec compliance
Related to sharing and isolation. Do you want to use application server classes where provided?
Non Spec compliance (except the servlet spec
You don't want to use application server classes or any shared classes. You want your own version.
Caller semantics
Call by reference
This is probably what you are familiar with one java class invokes a method on another.
Call by value
This simulates a remote invocation over the network. Parameters are "marshalled" - turned into a byte stream - then "unmarshalled" with destinations classloader. Any return value or exception is again "marshalled" then "unmarshalled" with the origin's classloader.
NOTE: You cannot use call-by-value for EJB local invocations. It simulates a remote call.
PROBLEMS WITH THESE ISSUES
Isolation
If you choose not to share you will have problems talking to other applications that don't have the same version of the class. The solution is to use call-by-value to "translate" the classes between the classloaders.
Spec compliance
If you choose not to use the application server classes, you will have problems talking to the application server itself.
Call by value
The extra work of object to bytestream translation is a cpu overhead. Typically you will need 10 times the cpu power (or 10 times the number of machines to run compared to an application that uses call-by-reference.
Servlet configuration
The servlet spec says that you shouldn't use JavaSE spec compliance. This essentially means it will use anything you put in
WEB-INF/classes
or
WEB-INF/lib
. Since these are usually "dumping grounds" for all sorts of "rubbish", this is usually a bad idea.
This isn't quite true since there is a configurable filter to ignore certain packages.
If you do want isolation, then configure that and share the application server classes.
Redeployment
If you share classes with another application, make sure you either don't redeploy the shared classes or you redeploy everybody when they change.
COMMON CONFIGURATIONS
Share everything
This is the default as long as you turn off the servlet spec classloader.
EAR Deployer - ease of use
Setting
isolated=true
and
call-by-value=true
on the
ear.deployer
and
enabling call-by-value for jndi will give you isolation and class translation for any applications deployed as ears.
Listing an deployment's contents
If you are relying on a jars ClassPath manifest header to pickup classes, its useful to display an overview of the archive contents including the ClassPath references. The attached ListJar ListJar.java, ListJar.class can be used for this. Run the ListJar program passing in the archive to list. For example:
[starksm@banshee9100 main]$ java -cp . ListJar cpmanifest.ear /cvs/JBoss4.0/jboss-4.0/testsuite/output/lib/cpmanifest.ear +- META-INF/MANIFEST.MF +- abstract.jar (archive) | +- META-INF/MANIFEST.MF | +- org/jboss/test/jmx/loading/AbstractBean.class +- concrete.jar (archive) | +- META-INF/MANIFEST.MF Class-Path: ./abstract.jar | +- org/jboss/test/jmx/loading/Concrete.class | +- org/jboss/test/jmx/loading/ConcreteBean.class | +- org/jboss/test/jmx/loading/ConcreteHome.class | +- META-INF/ejb-jar.xml +- META-INF/application.xml Done
This shows that the cpmanifest.ear/concrete.jar includes the abstract.jar via its Class-Path.
Other
The mechanisms for each deployment type are explained in the main classloading configuration link
More complicated
Sometimes you want isolation, but you still want to share amongst a select number of applications. To do this, assign them to same classloader repository with a specific name of your choosing, rather than using the automatic one created by
isolated=true
on the EARDeployer. This way you have your own little world to "play in".
Related
Comments