首页 > 代码库 > Jetty类加载

Jetty类加载

ssloader,系统classloader作为它的父亲。在Java中这样的层级关系是正常的,然而servlet规范复杂化了层级关系,因为它要求:
 1)包含在WEB-INF/lib或者WEB-INF/classes中的类优先于在父classloader上的类。这和通常的Java 2 classloader的行为是对立的。
 2)系统类例如java.lang.String被从webapp优先权中排除,你不可以使用在WEB-INF/lib或者WEB-INF/classes中的类代替它们。不幸的是规范没有清晰地陈述什么类是系统类,是否所有javax类都应该作为系统类对待。
 3)Server实现类像Server应该被从web应用隐藏,在任何classloader中都不应该是可用的。不幸的是规范没有陈述什么类是Server类,是否像Xerces解析器这样的公共库应该被作为实现类对待。

配置Webapp Classloading

Jetty提供配置选项控制上面列出的3个webapp类加载问题。
你能通过在WebAppContext上的几个方法配置webapp classloader。你能直接调用这几个方法,或者你能通过上下文XML文件配置。你不能从jetty-web.xml设置这些方法,因为它会在classloader配置被设置之后执行。

控制Webapp Classloader优先级

方法org.eclipse.jetty.webapp.WebAppContext.setParentLoaderPriority(boolean)允许你控制优先级。如果你设置它到false(默认),Jetty使用标准webapp类加载优先级。然而,如果在这种模式下一些被其它类依赖的类被父加载器加载(归因于下面的系统类设置),歧义可以出现于webapp和系统classloader版本都能结束被加载。
如果设置到true,Jetty使用通常的JavaSE类加载优先级,并给优先级到父/系统classloader。这避免了一个webapp内的一个类的多版本问题,但是父/系统加载器提供的版本必须是对所有webapp都正确的版本。

设置系统类

你能调用方法org.eclipse.jetty.webapp.WebAppContext.setSystemClasses(String Array)或者org.eclipse.jetty.webapp.WebAppContext.addSystemClass(String)来控制哪些类是系统类。
 1)一个web应用能看到一个系统类;
 2)一个WEB-INF类不能替代一个系统类。
默认系统类包括:

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.
被javax.xml需要。

org.w3c.
被javax.xml需要。

org.eclipse.jetty.continuation.
webapp能看见但不能改变continuation类。

org.eclipse.jetty.jndi.
webapp能看见但不能改变命名类。

org.eclipse.jetty.jaas.
webapp能看见但不能改变JAAS类。

org.eclipse.jetty.websocket.
WebSocket是一个Jetty扩展。

org.eclipse.jetty.servlet.DefaultServlet
webapp能看见但不能改变默认servlet。

绝对类名是合法的,名称以.结束被作为包名,名称以-开始作为否定匹配并必须在任何封闭的包之前列出。

设置Server类

你能调用方法org.eclipse.jetty.webapp.WebAppContext.setServerClasses(String Array)或者org.eclipse.jetty.webapp.WebAppContext.addServerClass(String)控制哪个类是Server类。
 1)web应用不能看到Server类;
 2)WEB-INF类能替代Server类。
默认Server类包括:

-org.eclipse.jetty.continuation.
不隐藏continuation类。

-org.eclipse.jetty.jndi.
不隐藏命名类。

-org.eclipse.jetty.jaas.
不隐藏jaas类。

-org.eclipse.jetty.servlets.
不隐藏servlet类,如果提供了。

-org.eclipse.jetty.servlet.
不隐藏默认servlet类。
 
-org.eclipse.jetty.servlet.listener.
不隐藏listeners

-org.eclipse.jetty.websocket.
不隐藏websocket扩展

org.eclipse.jetty. Do hide all other Jetty classes.
隐藏其它所有Jetty类。

增加额外的类路径到Jetty

你能增加额外的类路径到Jetty,有下面几种方式:

使用start.jar

如果你正在使用start.jar,在启动时jetty运行时自动从顶层$jetty.home/lib文件夹加载可选的Jar。默认的设置包括:
 1)增加Jar在$jetty.home/lib/ext下到系统类路径。你能放附加的Jar在这儿。
 2)增加文件夹$jetty.home/resources到类路径(可以包含类路径或者其它资源)。
 3)通过命令行参数path增加单个的路径定义。

使用extraClasspath()方法

你能增加一个附加的类路径到一个上下文classloader,通过使用一个逗号分隔的路径列表调用 org.eclipse.jetty.webapp.WebAppContext.setExtraClasspath(String)。你能通过上下文XML文件做到,如下;

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
 ...
 <Set name="extraClasspath>../my/classes,../my/jars/special.jar,../my/jars/other.jar>
 </Set>
 ...

使用自定义webapp classloader

如果上面提供的方式都不满足你的需求,你能为你的webapp提供一个自定义的classloader。我们推荐,但不要求,你的自定义加载器继承自WebAppClassLoader。你为你的应用配置classloader如下:

MyCleverClassLoader myCleverClassLoader = new MyCleverClassLoader();
 ...
   WebAppContext webapp = new WebAppContext();
 ...
   webapp.setClassLoader(myCleverClassLoader);

你也能在一个上下文xml文件中完成配置。

使用自定义ClassLoader启动Jetty

如果你使用自定义classloader启动Jetty server,考虑Jetty类对系统类加载器不是可用的,仅对你的自定义类加载器可用,当WebAppClassLoader进入时,你可能遇到类加载问题。默认WebAppClassLoader使用系统类加载器作为他的父亲,因此存在问题。这是容易修复的,采用如下方式:

context.setClassLoader(new WebAppClassLoader(this.getClass().getClassLoader(), context));

或者

context.setClassLoader(new WebAppClassLoader(new MyCustomClassLoader(), context));