Vous êtes sur la page 1sur 11

J2EE Class Loading Demystified 356/12/Friday 18h09

J2EE Class Loading Demystified


Level: Intermediate

Tim deBoer (deboer@ca.ibm.com), WebSphere Studio Development Team, IBM Toronto Lab
Gary Karasiuk (karasiuk@ca.ibm.com), WebSphere Studio Performance Analyst, IBM Toronto Lab
21 Aug 2002

Need help understanding how to use the J2EE-specified Web modules, EJB modules, and
applicationclient modules? This article explains the sophisticated techniques used by J2EE and
WebSphere Application Server for structuring and loading classes. Learn how to make the most
of the J2EE spec when building projects with WebSphere Studio Application Developer, and how
to avoid the ClassNotFoundException.

© 2002 International Business Machines Corporation. All rights reserved.

Introduction
Java class loading problems can be vexing, especially in advanced environments established to address
complex requests. Java 2 Platform Enterprise Edition (J2EE) and WebSphere© Application Server use
sophisticated techniques for structuring and loading classes. Like many developers, you're probably wondering
how to design your J2EE projects to make proper use of the various classloaders.

This article describes the J2EE specification and how you can use it to build projects inside WebSphere Studio
Application Developer (Application Developer). In addition to creating basic J2EE applications, this article
explores some best practices and advanced features of Application Developer. It also gives you a solid
foundation for tackling the dreaded ClassNotFoundException.

J2EE modules
The J2EE specification describes three types of modules: Web modules, Enterprise JavaBean (EJB) modules,
and application client modules. When deploying to a J2EE application server, all of these modules are
normally compressed into a single J2EE application Enterprise Architecture (EAR) file. The following sections
describe each type of module and how it is built using Application Developer.

Web modules
A Web module contains HTML, images, JSPs, JavaTM classes and servlets, and all other resources required to
create a Web application. Like the other modules, Web modules contain a deployment descriptor. In Web
modules, the deployment descriptor, web.xml, has servlet initialization and mapping information, and well
as other settings for running the Web module within an application server.

A Web module has two special folders for Java code: WEB-INF/classes and WEB-INF/lib. The
classes folder may contain "loose" Java classes (classes that are not inside a JAR file), and it can be used for
servlet or utility classes within the scope of the Web application. Often a special class loader is used for this
folder, so that if changes are made to the classes, they are automatically reloaded by the application server.
http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 1 sur 11
J2EE Class Loading Demystified 356/12/Friday 18h09

folder, so that if changes are made to the classes, they are automatically reloaded by the application server.
The lib folder may contain JAR files (not ZIP files!) that the Web application also uses. You should place
third-party JAR files and other utility JAR files in this folder. However, if other Web or EJB modules use the
JAR files, move them into the Enterprise Application project instead, as explained in the Enterprise
applications section below.

In Application Developer, Web modules are represented by Web projects, which contain two folders: source
and webApplication. The webApplication folder contains the complete J2EE Web module in its expanded
form. The source folder is used for .java files, as they often are not part of the deployed Web module. As
you create Java resources in this folder, they are automatically compiled and placed in the
webApplication/WEB-INF/classes folder. This keeps the Web project in sync at all times, and
ready for testing or exporting.

If you have imported your Web module from a Web Application Archive (WAR) file, you may notice that the
lib folder contains a projectname_classes.jar file. This file contains the original contents of the
imported WAR file. If the WAR file included source code, delete this file, as the classes will redundantly
appear in the classes folder.

EJB modules
EJB modules contain EJBs, their server-specific deployment code, a deployment descriptor, and optional
helper classes. They contain the business logic of your application, and are typically called by Web,
Application Client, or other EJB modules.

In Application Developer, an EJB module is represented by an EJB project. These projects also have two
folders, bin and ejbModule. The source of your EJB module is kept in the ejbModule folder. As you
make changes and generate deployment code, the Java classes from this folder are compiled into the bin
folder. Any remaining resources (for instance, the deployment descriptor) are also copied into the bin folder.
Similar to the Web project's webApplication folder, the bin folder always contains the complete
deployed EJB module. As with the Web project, you should not manually modify the bin folder in any way
as your changes may be lost. Make all changes within the ejbModule folder, and these changes will
automatically be compiled or copied into the bin folder.

If you import an EJB from an EJB JAR file, you may notice an Xxx_importedClasses.jar file
sitting in the root of your project. This file contains the original contents of the imported EJB JAR file. If the
JAR included source code, delete this file, as the classes will redundantly appear in the bin folder.

Application client modules


An application client module is used to contain a full-function client Java application (non Web-based) that
connects to and uses the J2EE resources defined in your server. By placing the client code in an application
client module instead of a simple JAR file, the application client benefits from the server's resources (it does
not need to re-specify the classpath to J2EE and server JAR files) as well as easier JNDI lookup (the server
fills in the initial context and other parameters).

In Application Developer, application client modules are represented by application client projects. For the
most part, you can work as if you are creating a standalone Java application in a Java project.

http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 2 sur 11


J2EE Class Loading Demystified 356/12/Friday 18h09

Enterprise (J2EE) applications


An enterprise application is a grouping of one or more Web, EJB, or application client modules. As a superset
of these other modules, it can contain a complete application that may be a combination of multiple modules.
Besides being an efficient grouping mechanism, enterprise applications make it much easier to deploy and
maintain code at the level of a complete application instead of as individual pieces. Enterprise applications can
also override settings within the contained modules' deployment descriptors to combine or deploy them in a
more useful way.

An enterprise application may contain JAR files that the contained modules will use. This allows sharing of
code at the application level, and is the best place to put utility JAR files that are used by multiple Web or
EJB modules. By placing these JAR files in the enterprise application instead of on the global classpath, they
are also within the J2EE specification, and do not require special publishing and setup when moving to a new
server.
In Application Developer, enterprise applications are represented by enterprise application projects. Since no
source code is built directly into an enterprise application, these projects do not have subfolders.

WebSphere classloaders
WebSphere Application Server uses several classloaders to enable the J2EE specification. Besides the regular
classloader that uses the CLASSPATH environment variable to locate and load classes, there are many other
classloaders at work.

Figure 1 shows a simplified diagram of the classloaders at work inside WebSphere. Each oval represents a
classloader, and the text in brackets describes where that classloader searches for classes:

Figure 1. WebSphere classloaders

http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 3 sur 11


J2EE Class Loading Demystified 356/12/Friday 18h09

At the top of Figure 1, the regular Java system classloader uses the CLASSPATH environment variable to load
classes. The second classloader is WebSphere-specific and uses a ws.ext.dirs environment variable to
load classes. In Application Developer, this environment variable is set by using the Server Instance Editor in
the Server Perspective. Besides loading any user code, this classloader also loads all of the WebSphere and
J2EE classes that are required at run time. The third classloader, AEX, may be used for application extensions.
It loads JARs from the <WAS>/lib/app directory. Finally, the modules running in the server are loaded
by one or more module classloaders. They follow the J2EE class loading rules discussed earlier to load the
classes and JAR files from your application.

The most important concept in Figure 1 above is that each classloader is defined as a child of the classloader
above it. A classloader can have delegation turned on or off. The first two classloaders (Java and WebSphere)
http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 4 sur 11
J2EE Class Loading Demystified 356/12/Friday 18h09

above it. A classloader can have delegation turned on or off. The first two classloaders (Java and WebSphere)
have it turned on and the last two (AEX and module) have it turned off.

When delegation is turned on, the classloader first delegates the request to its parent classloader. If none of the
parent classloaders can find the class, the original classloader attempts to load the class.

When delegation is turned off, the classloader first attempts to load the class itself. If it can't load the class, it
asks its parent to load the class.

In either case, requests can only go up the tree; they cannot go down. If the WebSphere classloader is
requested to find a class in a J2EE module, it cannot go down to the module classloader to find that class, and
a ClassNotFoundException will occur. After a class is loaded by a classloader, any new classes that it tries to
load will reuse the same classloader, or go up the chain until the class is found.

Given the above delegation properties, the effective search order becomes:

1) Module classloader
2) AEX -- Application Extensions classloader
3) Java classloader
4) WebSphere ws.ext.dirs classloader
There are two cases where you may run into problems:
WebSphere, J2EE, and any global classes cannot "see" the classes that are contained within your
applications. If you add a JAR file to the global classpath or ws.ext.dirs properties, it cannot
depend on classes within your modules.

If you need to globally add database drivers or utility JARs to the classpath, you must add them to the
ws.ext.dirs property, not to the global classpath. If you add them to the global classpath by
mistake, they won't be able to load (for example) the connection pooling classes in the J2EE JAR files.
Once again, this would appear as a ClassNotFoundException on the database driver, but it is a failure
for the database driver classes to see down to the J2EE classes.
A common portable technique for finding resources (property files, images, and so on) is to use the
classloader's findResourceXX methods. Based on the previous discussion, you can see why it is important to
use the right classloader for this job. For example, if you use the WebSphere classloader, you won't be able to
find any resources in your modules.

WebSphere classloader isolation modes


As mentioned earlier, WebSphere uses several classloaders to load the application code from the modules
deployed to the server. The number and function of these classloaders depends on the classloader isolation
mode (otherwise known as module visibility mode) that has been specified in the WebSphere server
configuration. There are four settings you can choose:
Server -- uses the same classloader for the entire server.
Application -- uses a separate classloader for each Enterprise application.
Module -- uses a separate classloader for each module.
Compatibility -- uses the same classloader scheme as WebSphere Application Server 3.0.x and 3.5.x.
This allows code to have visibility across enterprise application boundaries. This mode is not
recommended unless you are migrating code from older servers.

http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 5 sur 11


J2EE Class Loading Demystified 356/12/Friday 18h09

Module interdependencies
When you are building applications that span multiple modules within an enterprise application, ensure that
the classes within one module can see the classes that it uses from another module. This is also true for a
module that wants to use a JAR file out of the enterprise application. This must be done for compile time as
well as for run time.

At compile time, updating the classpath is simple. All you have to do is edit your project's properties and
change the Java build path to include the other project or JAR file, but don't touch that dial yet! This article
introduces a much easier way to update this at compile time and run time in a single step. In general, don't
change the Java build path of a J2EE project by hand. The steps in this section will automatically update and
maintain the build path and keep it in sync with the run time.

At run time, your applications must follow the J2EE specification when referring to other modules. As
discussed in the WebSphere classloaders section, do not simply place a project on one of the global classpaths,
as this could have disastrous effects, both on classloading and on making your code visible to all other
applications.

You also should not rely on the WebSphere classloader isolation modes. If your server is running in (for
example) application mode, you may not need to make any changes to allow your application to work at run
time. Do not rely on this! You may later need to deploy your application to a server running in module mode,
and you will find that your application no longer works. Follow the steps below to ensure that your application
is correct, regardless of the isolation mode you are using.

The solution is to make use of the fact that J2EE modules are JAR files. All JAR files may have a META-INF
folder that contains a MANIFEST.MF file, and the manifest file may contain a classpath that refers to other
JARs. By adding one of the other modules as an entry in the manifest's classpath, the current module can make
use of its contained classes. You can also add JAR files from within the enterprise application to the manifest.
The only restriction to this otherwise simple solution is that, since Web modules are not structured with classes
at their root, other modules can never depend on classes from within Web modules. In other words, no
modules may use the manifest to depend on classes from within a Web module.
Application Developer provides an easy way to update the manifest file. Right-click on a J2EE project from
within the Navigator or J2EE view, and select Edit Module Dependencies. This brings up a dialog (see
Figure 2 below) that shows a checkbox list containing all other modules and JAR files that this project can
depend on. By selecting the modules or JAR files in the list, both the manifest and build path are updated at
the same time. This ensures that the manifest and build path are always in sync, and provides an easier way to
change the dependencies of your project.

Figure 2. Edit Module Dependencies dialog

http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 6 sur 11


J2EE Class Loading Demystified 356/12/Friday 18h09

Where should I put my JAR files?


If your JAR file is only used in a single Web application, always put the JAR file in the Web project's
webApplication/WEB-INF/lib folder. JAR files in this folder are automatically added to the Java
build path, and will not require any further setup when moving to a different server.

If the JAR file is used by multiple modules within the same application, put the JAR file in the enterprise
application. You will need to use the Edit Module Dependencies feature to set up the manifest files and the
Java build classpaths.
You can also put the JAR on one of the global classpath, but we don't recommend this. It complicates your
deployment and leaves your application vulnerable to incompatibility problems if those JARs are later
upgraded. For example, suppose that you depend on some third-party logging classes, and since these logging
classes are used by almost all applications, you decide to deploy them on a global classpath. You test your
application with version 1 of the logging classes. Six months later another application is deployed and it
requires version 2 of the logging classes, so the logging JAR is updated. Your application is now running in
http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 7 sur 11
J2EE Class Loading Demystified 356/12/Friday 18h09

requires version 2 of the logging classes, so the logging JAR is updated. Your application is now running in
an environment in which it was never tested.
If you still want to put the JAR file on the global classpath, you must decide whether it should go on the
classpath or ws.ext.dirs. This decision is simple. If the JAR file needs to access any J2EE or
WebSphere classes, or any other JARs that have been added to ws.ext.dirs, it must also be placed on
the ws.ext.dirs property. Otherwise, you are free to use either property.
If you have dependencies on the JAR file, update the Java build path of each project that uses the JAR file.
Adding it to the global classpath or ws.ext.dirs properties also means that you will have to publish the
JAR file separately from your application, and you will have to set up the server classpath again when you
move to a different server.

Classes or JARs?
Another decision you need to make is whether to use loose classes or JARs. The big advantage of using loose
classes is that they are easier to debug and deploy. With a loose class, you make your change, press Ctrl-S,
and if it is on a reloadable classpath (like WEB-INF/classes) it is available immediately. If it is not on a
reloadable classpath, and if you are using WebSphere Application Server, you only have to restart the project
and then the changes are available. To do this, right-click on the project from within the Navigator, and select
Restart Project from the pop-up menu.
If you are using JAR files, you are faced with the additional build step of gathering all of the classes and
rebuilding the JAR file. Your changes aren't available quite as quickly. The advantage of using JAR files is
that deployment is a little cleaner, and closer to what your production environment would expect.

If you are in the early stages of a project where your helper classes are changing frequently, you will find it
more convenient to use loose classes. If the classes are only used by a single Web module, place the classes in
the WEB-INF/classes folder. Always use packages for your classes, as the Java spec is imprecise when
it comes to dealing with classes in the default package.
If the classes are used by your EJBs, then make one of your EJB projects hold the helper classes (place them
under the ejbModule folder), and have the other EJB modules that need those helper classes depend on that
EJB project. Collect all of your helper classes in a single EJB project, because it is very important not to have
circular dependencies between your projects. Good project structure dictates that dependencies must always be
in the form of a tree. Once the helper classes mature and aren't changing as much, switch to a JAR approach.
What if you have utility classes that are used both by enterprise applications and normal Java applications?
The simplest approach is to use JARs for those classes.

Development time versus run-time classpaths


At compile time, a Java compiler needs to know about every class or JAR file that your code refers to, so that
it can safely compile and type-check against these classes. The Java compiler uses the project level property
Java Build Path as its one and only source for this information. Other operations, like Edit Module
Dependencies, manipulate the build path, but the build path is the authoritative source.

At run time, the application server uses a completely different mechanism to find and load classes. The run
time doesn't know anything about the Java build path, and therefore your application may compile correctly,
but still have ClassNotFoundExceptions at run time.

http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 8 sur 11


J2EE Class Loading Demystified 356/12/Friday 18h09

Conclusion
Now that you understand how the various classloaders work together, you should be in a much better position
to understand how to structure your projects and avoid the dreaded ClassNotFoundException.

Questions from users


Question 1: When you say "Follow the steps below to ensure that your application is correct, regardless of the
isolation mode you are using," how can you guarantee that two enterprise applications that use different
versions of the same JAR will work together in the same VM if the WebSphere classloader isolation mode is
set to "Server"? Won't there be conflicts as each enterprise app tries to load its own version of the same JAR
using a single classloader (single VM)?
Response from author: Excellent point. When you switch to "Server" classloading mode, you are basically
giving up all rights to run two different versions of the same JAR or class. Of all the possible modes, this one
puts restrictions on deploying multiple applications together. I guess that we missed saying it in the article, but
I strongly suggest avoiding "Server" classloading unless there is something in your application that demands it,
and even then I would try to change the application first. This is the one case where even a well-coded
application could have problems running on the server.

Question 2: Where do you mention the order of loading -- Web, EJB, and application client modules? You say
"They follow the J2EE classloading rules discussed earlier to load the classes and JAR files from your
application." Where is the "discussed earlier" section? I couldn#x2019t find it anywhere.

Response from author: Sorry if this the article is not helping to explain J2EE and WebSphere Application
Server classloading. I hope I can clear up some issues by answering your questions. J2EE does not define any
application loading order, and you should not build your applications to depend on one. If you do need to
depend on the ordering, contact WebSphere Application Server Support to see if they can help you define the
ordering. The section "discussed earlier" is the discussion of the various J2EE modules and their contents. The
classloading rules define the locations within each module type where it is valid to put class files and JARs.
J2EE defines these locations, and putting classes or JARs outside of them will prevent the objects from getting
loaded at run time. When developing with WebSphere Studio, these locations become folders within the
expanded J2EE module structure of the project, so it's important to know about these locations.

Question 3: I'd like to know more about what is specifically in the J2EE spec vs. what is an extension
provided by WebSphere.

Response from author: Check the full J2EE documentation and specifications, which are based on the
standard J2SE specification. They are a bit much to read -- there are a number of books and online tutorials
that summarize them. Anything that is not included or implied by these two specs is WebSphere specific.
When you are using WebSphere Studio for development, the majority of the WebSphere-specific features
(such as EAR reloading settings in the EAR deployment descriptor editor) have been specifically named or
grouped to make it clear that they are extensions to the spec. Other features, such as layout of the projects in
the IDE and specific classloading modes, are not laid out by the specs, but evolve out of writing the
appropriate development tool or runtime to manage the artifacts in the specs. If you have questions about
specific features or settings, try posting to one of the WebSphere newsgroups or contacting WebSphere
Support.

http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 9 sur 11


J2EE Class Loading Demystified 356/12/Friday 18h09

Question 4: Is a similar article available for WebSphere Studio V5.0? I have created three Web projects with
one having common class files and the other two using those common class files. I have set up proper project
references in the Java build path and the projects build perfectly. But when I deploy the projects, I get a "class
not found" error for the classes in the common Java project.

Response from author: There is no similar article for WebSphere Studio V5.0. Adding the project to the Java
build path does exactly that -- it adds it to the compile time build path, and does not make any changes that
would affect the running of the project. In this case, the utility classes are not being found because they are
not visible as utility JARs within the Web or EAR projects. WebSphere Studio V5.0 has a new option to set up
Java utility projects. It's in the EAR and Web Deployment Descriptor Editors, and it lets a Java project build
and run as if it were a utility JAR within the EAR or Web project. On export, the utility Java project is
packaged up as a JAR file according to spec. For additional information about this feature, see the WebSphere
Studio V5.0 online help.
Question 5: If I need to associate property files with my EAR file, like for database connectivity, this path of
the file could be given in the server classpath and made available. Is there any better way of doing this, like
making it part of the EAR file?

Response from author: Yes, property files can be made part of the EAR file. This is equivalent to putting
utility classes or a utility JAR file in the EAR file. Here are the basic steps:
1 . Add the property files to the EAR file as a JAR file or within a directory.
2 . Update the manifest file of the module that needs access to the property file to contain the run-time
relative path to the folder or JAR file within the EAR file. Doing this will add the property file to the
classpath of that module.
3 . Use Class.getResourceAsStream() from the module to load the properties file from its
classpath.
Top of page

Resources

About the authors


Tim deBoer is a software developer on the WebSphere Studio Application Developer,
Server Tools team at the IBM Toronto Lab. With his teammates, he is currently
responsible for the WebSphere and Tomcat test environments and the EJB test client.
You can contact Tim at deboer@ca.ibm.com .

Gary Karasiuk is a performance analyst for WebSphere Studio Application Developer. You
can contact Gary at karasiuk@ca.ibm.com .

http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 10 sur 11


J2EE Class Loading Demystified 356/12/Friday 18h09

http://www-128.ibm.com/developerworks/websphere/library/techarticles/0112_deboer/deboer.html Page 11 sur 11

Vous aimerez peut-être aussi