问题导出
关于主流的Java Web服务器Tomcat、Jetty、WebLogic、WebSphere等,先提出几个问题:
- 部署在同一个服务器上的两个Web应用程序所使用的Java类库是如何实现相互独立?
- 部署在同一个服务器上的两个Web应用程序所使用的Java类库是如何实现相互共享?
- 服务器如何保证自身的安全不受部署的Web应用程序的影响?
- 支持JSP应用的Web服务器,如何支持HotSwap功能的?
上述问题,可以由Web服务器的类加载系统来实现。例如,Tomcat的ClassLoader体系结构如下所示:
首先回顾一下Jvm标准的类加载体系。
Jvm ClassLoader
1) ClassLoader
Java类装载器在Java安全体系结构中起着最关重要的作用,是Java安全沙箱的第一道防线。类装载器体系结构在三个方面对Java的沙箱起作用:
- 它防止恶意代码去干涉善意的代码
- 它守护了被信任的类库的边界
- 它将代码归入某类(称为保护域),该类确定了代码可以进行哪些操作
类装载器体系结构可以防止恶意代码去干涉善意的代码,这是通过为不同的类装载器装入的类提供不同的命名空间来实现的。
Btw: 另外一种加载类的方法:Class.forName,
Class.forName
的一个很常见的用法用来加载数据库驱动。
2) ClassLoader体系结构
- 启动类加载器(BootStrap ClassLoader): 是最顶层的类加载器,由C++编写而成,并不继承自
java.lang.ClassLoader,
并且已经内嵌到JVM中了。主要用来读取Java的核心类库jre/lib/rt.jar - 扩展类加载器(Extension ClassLoader): 是用来读取Java的扩展类库,读取jre/lib/ext/*.jar
- 系统类加载器(App ClassLoader): 它根据Java应用的类路径(classpath)来加载Java类。一般来说,Java应用的类都是由它来完成加载的。可以通过
ClassLoader.getSystemClassLoader()
来获取它。 - 自定义类加载器(Custom ClassLoader): 开发人员可以通过继承
java.lang.ClassLoader
类的方式实现自己的类加载器,以满足一些特殊的需求。
3) 双亲委派模型
从1.2版本开始,Java引入了双亲委派模型,从而更好的保证Java平台的安全。
在此模型下,当一个装载器被请求装载某个类时,它首先委托自己的parent去装载,若parent能装载,则返回这个类所对应的Class对象,若parent不能装载,则由parent的请求者去装载,如果此时自己也不能加载,则产生java.lang.NoClassDefFoundError。具体委托逻辑在java.lang.ClassLoader的loadClass(String name,boolean resolve)方法中:
例如,java.lang.String这个类是由Bootstrap ClassLoader加载的,它是最终的父加载器,如果用户自己写一个java.lang.String从自定义的类加载器加载,那么根据双亲委派模型,真正的String由Bootstrap ClassLoader加载,而自定义的java.lang.String永远加载不进来。
双亲委派模型有一个缺陷,如果父ClassLoader想加载子ClassLoader中的类比较困难,而在有的应用中这种加载方式是需要的,比如JNDI,Servlet.
4) 全盘负责
所谓全盘负责,即当一个ClassLoader加载一个Class的时候,这个Class所依赖和引用的所有Class也由这个ClassLoader负责载入,除非显示的使用另外一个ClassLoader载入。例如,由于java.lang.String是由Bootstrap ClassLoader载入的,那么String中引用的类如CharSequence等默认都是使用Bootstrap ClassLoader载入。
5) 命名空间
由不同的类装载器装载的类将被放在虚拟机内部的不同命名空间。命名空间由一系列唯一的名称组成,每一个被装载的类有一个名字。JAVA虚拟机为每一个类装载器维护一个名字空间。例如,一旦JAVA虚拟机将一个名为Volcano的类装入一个特定的命名空间,它就不能再装载名为Valcano的其他类到相同的命名空间了。可以把多个Valcano类装入一个JAVA虚拟机中,因为可以通过创建多个类装载器从而在一个JAVA应用程序中创建多个命名空间。
Jetty类加载器
Jetty的ClassLoader架构
Jetty,Tomcat等web容器通常都会对ClassLoader做扩展,因为一个正常的容器至少要保证其内部运行的多个webapp之间:私有的类库不受影响,并且公有的类库可以共享。这正好发挥ClassLoader的层级划分优势。 Jetty中有一个org.mortbay.jetty.webapp.WebAppClassLoader,负责加载一个webapp context中的应用类,WebAppClassLoader以系统类加载器作为parent,用于加载系统类。不过servlet规范使得web容器的ClassLoader比正常的ClassLoader委托模型稍稍复杂,servlet规范要求:
- WEB-INF/lib和WEB-INF/classes优先于父容器中的类加载,比如WEB-INF/classes下有个XYZ类,classpath下也有个XYZ类,jetty中优先加载的是WEB-INF/classes下的,这与正常的父加载器优先相反(childfirst)。
- 系统类比如java.lang.String不遵循第一条, WEB-INF/classes或WEB-INF/lib下的类不能替换系统类。不过规范中没有明确规定哪些是系统类,jetty中的实现是按照类的全路径名判断。
- Server的实现类不被应用中的类引用,即Server的实现类不能被人和应用类加载器加载。不过,同样的,规范里没有明确规定哪些是Server的实现类,jetty中同样是按照类的全路径名判断。
为了处理上述三个问题,jetty的应用类加载器(org.mortbay.jetty.webapp.WebAppClassLoader)做了些特殊处理。
Jetty的ClassLoader体系结构如下所示:
WebAppClassLoader的实现
WebAppClassLoader的构造器
WebAppClassLoader还是按照正常的范式设置parent ClassLoader,如果当前线程上下文中设定了ClassLoader就以当前线程上下文类加载器为父ClassLoader,否则使用WebAppClassLoader的加载器,如果还没有,就采用系统类加载器。
下面看一下WebAppClassLoader的loadClass()方法:
ClassLoader Priority
上述过程涉及一个加载器优先级的概念,这也是针对前述第一条规范中WEB-INF/lib和WEB-INF/classes类优先的处理。jetty中父加载器优先的配置项可以通过环境变量
org.eclipse.jetty.server.webapp.parentLoaderPriority=false(默认)/true来设置
也可以通过
org.eclipse.jetty.webapp.WebAppContext.setParentLoaderPriority(boolean)方法来设置
优于该配置默认是false,因此在load class过程中优先使用WebAppClassLoader加载WEB-INF/lib和WEB-INF/classes中的类。 当将该配置项设为true时需要确认类加载顺序没有问题。
小结:
如果是parentfirst或者system_class并且不是server_class,则采用parentfirst策略加载;
如果是childfirst,则加载顺序为:WebAppClassLoader-->bootstraploader-->ExtClassLoader-->AppClassLoader
设置系统类
规范2中约定系统类不能被应用类覆盖,但是没有明确规定哪些时系统类,jetty中以类的package路径名来区分,当类的package路径名位包含于以下路径时,会被认为是系统类。WebAppContext中配置如下:
因此,我们可以通过 org.eclipse.jetty.webapp.WebAppContext.setSystemClasses(String Array)或者org.eclipse.jetty.webapp.WebAppContext.addSystemClass(String)来设置系统类。 系统类是对多有应用都可见。
设置Server类
规范3中约定Server类不对任何应用可见。Jetty同样是用package路径名来区分哪些是Server类。WebAppContext中配置如下:
我们可以通过, org.eclipse.jetty.webapp.WebAppContext.setServerClasses(String Array) 或org.eclipse.jetty.webapp.WebAppContext.addServerClass(String)方法设置Server类。 注意,Server类是对所有应用都不可见的,但是WEB-INF/lib下的类可以替换Server类。
自定义WebApp ClassLoader
当默认的WebAppClassLoader不能满足需求时,可以自定义WebApp ClassLoader,不过Jetty建议自定义的ClassLoader要扩展于默认的WebAppClassLoader实现。
参考
http://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 深入探讨Java类加载器
相关推荐
NULL 博文链接:https://nbaertuo.iteye.com/blog/366847
jetty-security-9.4.8.v20171121.jar,jetty-io-9.4.8.v20171121.jar,jetty-continuation-9.4.8.v20171121.jar,jetty-client-9.4.8.v20171121.jar,jetty-jmx-9.4.8.v20171121.jar,jetty-plus-9.4.8.v20171121....
jetty-9.4.6
eclipse jetty插件,从...下载run-jetty-run.zip文件,解压后再编写个links文件丢到eclipse的dropins目录下即可,省去了使用eclipse update方式安装的麻烦。 link文件样例如: path=d:\\eclipse_plugins\\run-jetty-run
Jetty软件包内容: jetty-distribution-9.4.51.v20230217.tar.gz jetty-distribution-9.4.51.v20230217.zip jetty-home-10.0.15.tar.gz jetty-home-10.0.15.zip jetty-home-11.0.15.tar.gz jetty-home-11.0.15.zip ...
jetty是什么 jetty配置 jetty使用 jetty嵌入 jetty启动 jetty部署 jetty教程 jetty嵌入式 jetty
Jetty是一个纯Java实现的开源Servlet容器,Jetty也可以作为HTTP服务器和HTTP客户端,Jetty仪器轻巧...众所周知因为安全的原因,多数浏览器都限制了Ajax跨域请求和javascript加载的时候只能是与当前域下的应用进行交互。
jetty嵌入式服务器开发所必须的jar包,本人使用jetty版本为6.1.3,jar包总数为9个,来自jetty:commons-el-1.0.jar,jasper-compiler-5.5.15,jasper-compiler-jdt-5.5.15.jar,jasper-runtime-5.5.15.jar,jetty-...
jetty相关所有jar包,包含jar包: jetty-continuation-8.1.15.v20140411,jetty-http-8.1.15.v20140411,jetty-io-8.1.15.v20140411,jetty-security-8.1.15.v20140411,jetty-server-8.1.15.v20140411,jetty-util-8.1.15...
.jetty
Jetty配置支持HTTPS以及受信网站证书生成方式
maven集成jetty必须jar包maven-jetty-plugin,内含多个版本
jetty 学习资料合集 jetty 学习资料合集 jetty 学习资料合集 jetty 学习资料合集
android i-jetty servlet-api-2.5.jar jetty-servlet-7.6.0.RC4.jar jetty-server-7.6.0.RC4.jar jetty-http-7.6.0.RC4.jar
jetty服务器,9.2版本适合java7+开发环境。 Jetty是一个纯粹的基于Java的网页服务器和Java Servlet容器。 尽管网页服务器通常用来为人们呈现文档,但是Jetty通常在较大的软件框架中用于计算机与计算机之间的通信。 ...
Jetty嵌入项目代码中示例,现我有一示例项目 e:/workspace/web-demo(称为project_home),里面的Web根目录是WebContent。 在project_home建一个jetty目录,子目录如:contexts、etc、lib。 把${jetty_home}/etc...
Jetty9 配置使用HTTPS证书,访问你的服务器更安全,更好的配置方法。
jetty 9.4.9, jetty 容器是轻便型容器,启动速度的确可以 ,附带有servlet-api.jar 和jsp-api.jar 两个jar包
jetty源代码下载 jetty源代码下载 jetty源代码下载 jetty源代码下载
自己写的jetty6在eclipse启动中配置说明