Class loading in a web container is slightly more complex than a normal java application.
The normal configuration is for each web context (web application or war file) is given it's own classloader, which has the system classloader as it's parent. Such a classloader hierarchy is normal in Java, however the servlet specification complicates the hierarchy by requiring that:
- Classes contained within WEB-INF/lib or WEB-INF/classes have priority over classes on the parent class loader. This is the opposite of the normal behaviour of a java 2 class loader.
- System classes such as java.lang.String are excluded from the webapp priority and may not be replaced by classes in WEB-INF/lib or WEB-INF/classes. Unfortunately the specification does not clearly state what classes are "System" classes and it is unclear if all javax classes should be treated as System classes.
- Server implementation classes like org.eclipse.jetty.server.Server should be hidden from the web application and should not be available in any class loader. Unfortunately the specification does not state what is a Server class and it is unclear if common libraries like the xerces parser should be treated as Implementation classes.
Jetty provides configuration options to control the three webapp classloading issues identified above.
Configuring Webapp Classloading
Webapp classloading can be configured by several methods on the org.eclipse.jetty.webapp.WebAppContext. These methods can be called directly if working with the Jetty API, or injected from a context xml file if using the Context Deployer. They CANNOT be set from a jetty-web.xml file, as that is executed after the classloader configuration is set.
Controlling Webapp classloader priority
The method org.eclipse.jetty.webapp.WebAppContext.setParentLoaderPriority(boolean) allows control over the priority given to webapp classes over system classes. If this is set to false (the default), then standard webapp classloading priority is used, however if in this mode some classes that are dependencies of other classes loaded from the parent classloader (due to settings of system classes below), then ambiguities may arise as both the webapp and system classloader version may end up being loaded.
If set to true, then normal JavaSE classloading priority is used and priority is given to the parent/system classloader. This avoids the issues of multiple versions of a class within a webapp, but the version provided by the parent/system loader must be the right version for all webapps configured in this way.
Setting System Classes
The methods org.eclipse.jetty.webapp.WebAppContext.setSystemClasses(String Array) or org.eclipse.jetty.webapp.WebAppContext.addSystemClass(String) may be called to allow fine control over what classes are considered System classes. A System class can be seen by a web application, but cannot be replaced by any WEB-INF class. The default system classes are:
|java.||Java SE classes (per servlet spec v2.5 / SRV.9.7.2)|
|javax.||Java SE classes (per servlet spec v2.5 / SRV.9.7.2)|
|org.xml.||needed by javax.xml|
|org.w3c.||needed by javax.xml|
|org.eclipse.jetty.continuation.||webapp can see and not change continuation classes|
|org.eclipse.jetty.jndi.||webapp can see and not change naming classes|
|org.eclipse.jetty.plus.jaas.||webapp can see and not change jaas classes|
|org.eclipse.jetty.websocket.||WebSocket is a jetty extension|
|org.eclipse.jetty.servlet.DefaultServlet||webapp can see and not change default servlet|
Absolute classname can be passed, names ending with . are treated as packages names and names starting with - are treated as negative matches and must be listed before any enclosing packages.
Setting Server Classes
The methods org.eclipse.jetty.webapp.WebAppContext.setServerClasses(String Array) or org.eclipse.jetty.webapp.WebAppContext.addServerClass(String) may be called to allow fine control over what classes are considered Server classes. A Server class can not be seen by a web application, but can be replaced by a WEB-INF class. The default server classes are:
|-org.eclipse.jetty.continuation.||don't hide continuation classes|
|-org.eclipse.jetty.jndi.||don't hide naming classes|
|-org.eclipse.jetty.plus.jaas.||don't hide jaas classes|
|-org.eclipse.jetty.websocket.||don't hide websocket extension|
|-org.eclipse.jetty.servlet.DefaultServlet||don't hide default servlet|
|org.eclipse.jetty.||hide all other jetty classes|
Adding extra classpaths to Jetty
At startup, the jetty runtime will automatically load all jars from the top level $jetty.home/lib, along with certain subdirectories such as $jetty.home/lib/management/, $jetty.home/lib/naming/ etc, which are named explicity in the [start.config|A look at the start.jar mechanism] file contained in the start.jar. In addition, it will recursively load all jars from $jetty.home/lib/ext. So, to add extra jars to jetty, you can simply create a file hierarchy as deep as you wish within $jetty.home/lib/ext to contain these jars. Of course, you can always change this default behaviour by [creating your own start.config|A look at the start.jar mechanism] file and using that instead. Otherwise, you can use one of the methods below.
Using jetty.class.path System property
If you want to add a couple of class directories or jars to jetty, but you can't put them in $jetty.home/lib/ext/ for some reason, or you don't want to create a custom start.config file, you can simply use the System property Template:-Djetty.class.path on the runline instead. Here's how it would look:
java -Djetty.class.path="../my/classes:../my/jars/special.jar:../my/jars/other.jar" -jar start.jar
Using the extraClasspath() method on WebAppContext
If you need to add some jars or classes that for some reason are not in $jetty.home/lib nor inside your webapp's WEB-INF/lib or WEB-INF/classes, you can add them directly to your webapp in a $JETTY_HOME/contexts/mycontext.xml file:
<Configure class="org.mortbay.jetty.webapp.WebAppContext"> ... <Set name="extraClasspath">../my/classes:../my/jars/special.jar:../my/jars/other.jar</Set> ...
Using a custom WebAppClassLoader
Finally, if none of the other alternatives already described meet your needs, you can always provide a custom classloader for your webapp. It is recommended, but not required, that your custom loader subclasses [org.mortbay.jetty.webapp.WebAppClassLoader|http://jetty.mortbay.org/apidocs/org/mortbay/jetty/webapp/WebAppClassLoader.html]. You configure the classloader for the webapp like so:
MyCleverClassLoader myCleverClassLoader = new MyCleverClassLoader(); ... WebAppContext webapp = new WebAppContext(); ... webapp.setClassLoader(myCleverClassLoader);