`

浅谈运行环境的类加载

阅读更多
   在我们搭建运行环境时,有时候会碰到各种各样的问题,比较常见的是ClassNotFoundException和NoClassDefFoundException,这样的问题还是比较简单的,一般我们只要查看一下缺少的类,将类包放进加载目录就可以的。有的问题就比较奇怪了,譬如说,在启动的时候,一点错误也没有,但是起来之后却提示404,无法访问;再就是,启动的时候每条日志都会重复打印,而且起来之后怎么也登录不进去等等。其实只要了解了java和Web 应用服务器的类加载机制之后,套用神探狄仁杰的一句话说“这些看似不可思议的问题背后,其实都有一个合理的原因”。那么接下来,我来介绍一下我所了解的java及Web 应用服务器的类加载机制。
    Java 中的系统提供的类加载器主要有下面三个:
引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader。
扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader() 来获取它。
除了引导类加载器之外,所有的类加载器都有一个父类加载器。对于系统提供的类加载器来说,系统类加载器的父类加载器是扩展类加载器,而扩展类加载器的父类加载器是引导类加载器;对于开发人员编写的类加载器来说,其父类加载器是加载此类加载器 Java 类的类加载器。因为类加载器 Java 类如同其它的 Java 类一样,也是要由类加载器来加载的。一般来说,开发人员编写的类加载器的父类加载器是系统类加载器。类加载器通过这种方式组织起来,形成树状结构。树的根节点就是引导类加载器。图 1 中给出了一个典型的类加载器树状组织结构示意图,其中的箭头指向的是父类加载器。

    类加载器在尝试自己去查找某个类的字节代码并定义它时,会先代理给其父类加载器,由父类加载器先去尝试加载这个类,依次类推。那么Java 虚拟机是如何判定两个 Java 类是相同的。Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。即便是同样的字节代码,被不同的类加载器加载之后所得到的类,也是不同的。
    对于运行在 Java EE 容器中的 Web 应用来说,类加载器的实现方式与一般的 Java 应用有所不同。不同的 Web 容器的实现方式也会有所不同。以 Apache Tomcat 来说,每个 Web 应用都有一个对应的类加载器实例。该类加载器也使用代理模式,所不同的是它是首先尝试去加载某个类,如果找不到再代理给父类加载器。这与一般类加载器的顺序是相反的。这是 Java Servlet 规范中的推荐做法,其目的是使得 Web 应用自己的类的优先级高于 Web 容器提供的类。这种代理模式的一个例外是:Java 核心库的类是不在查找范围之内的。这也是为了保证 Java 核心库的类型安全。
    绝大多数情况下,Web 应用的开发人员不需要考虑与类加载器相关的细节。下面给出几条简单的原则:
每个 Web 应用自己的 Java 类文件和使用的库的 jar 包,分别放在 WEB-INF/classes 和 WEB-INF/lib 目录下面。
多个应用共享的 Java 类文件和 jar 包,分别放在 Web 容器指定的由所有 Web 应用共享的目录下面。
    看到这里,有的同事可能就会问了,等等等等,类存放还要分共享和私有,太麻烦了,能不能放到一个路径下,譬如说全部放到WEB-INF/lib下或者全部放到共享目录下。听起来好像也没有什么问题,反正都是能够被系统加载的,只要放全了,放哪不行啊。那么真的可行吗?
    其实对于单个web应用,确实放哪都可以,因为对于单个web应用是没有共享和私有的区分的,只要把该放的类放全了,那么类就可以被正确的加载和使用。但是当一个web服务下存在多个应用时,问题就来啦。首先假如把类全部放在共享的classPath下,那么就会出现我们开头所提到的“在启动的时候,一点错误也没有,但是起来之后却提示404”的问题,为什么?因为我们的web服务在加载的时候只加载了一份webwork相关的类,这导致了这些类在初始化的时候,只初始化了一个web应用的action配置,当我们要访问web服务中的另外一个应用时,系统只好告诉你“Could not execute action”了,因为他根本不知道这个世界上还有另外一个应用存在。那么反过来,我们把全部的类都放到WEB-INF/lib下总万事大吉了吧,我用我的全部类,你用你的全部类,无非是容器累一点,多加载一份类而已。OK,真的能够如愿以偿吗。不是的,举个简单的例子,在我们zjport一期的单点登录中使用了globalSession,这是保存在web容器的单个共享实例中的,假如我们人为的将这些共享类放到私有的加载路径下,这就会导致“启动的时候每条日志都会重复打印,而且起来之后怎么也登录不进去”,因为globalSession不共享了,所以当我们登录到zjport之后,由于我们的菜单配置有个默认显示页面,这个页面可能不是zjport本身这个应用的,这时候单点登录就会校验不通过,马上就跳到起始的登录页面。
    本文的理论部分参考:http://www.ibm.com/developerworks/cn/java/j-lo-classloader/?ca=drs-tp4608#download
分享到:
评论
发表评论

文章已被作者锁定,不允许评论。

相关推荐

    浅谈数据库设计.doc

    浅谈数据库设计 在当今的信息时代,信息已逐渐成为决定生产力、竞争力和经济效益的重要资源,管 理者只有及时、准确地掌握相关信息,才能做出正确的决策。数据库技术是指对于一个 给定的应用环境,构造最优的数据库...

    浅谈大数据及大数据分析.doc

    浅谈大数据及大数据分析 作者:吕跃超 来源:《电脑知识与技术》2018年第18期 摘要:认识当今的大数据环境、新型分析方法的基本原理和商机、所需的角色 ,以及垂直行业中具有代表性的大数据分析示例。明确大数据,...

    浅谈关于C#的垃圾回收机制

    理解C#垃圾回收机制我们首先说一下CLR(公共语言运行时,Common Language Runtime)它和Java虚拟机一样是一个运行时环境,核心功能包括:内存管理、程序集加载、安全性、异步处理和线程同步。 CTS(Common Type ...

    嵌入式系统/ARM技术中的浅谈PxA255的U-B00t启动分析及移植

     Bootloader是操作系统运行之前执行的一小段程序,用来初始化硬件设备,建立一个系统空间映射图和一个适当的系统软硬件环境。最终Bootloader把操作系统内核映像加载到RAM中。并将系统控制权交给内核。BootLoader...

    我的编程感悟(中文PDF)(共37M二分卷)分卷二

    6.1 浅谈代码优化 138 6.2 并不仅仅是汇编 139 6.2.1 在算法实现时减少上下文的依赖关系 139 6.2.2 低效的静态变量 140 6.2.3 数据的组织 141 6.2.4 消除除法 142 6.2.5 避免过大的循环 144 6.3 汇编和C/C++的混合...

    我的编程感悟(中文PDF)(共37M二分卷)分卷一

    6.1 浅谈代码优化 138 6.2 并不仅仅是汇编 139 6.2.1 在算法实现时减少上下文的依赖关系 139 6.2.2 低效的静态变量 140 6.2.3 数据的组织 141 6.2.4 消除除法 142 6.2.5 避免过大的循环 144 6.3 汇编和C/C++的混合...

    asp.net知识库

    asp.net 运行机制初探(httpModule加载) 利用反射来查看对象中的私有变量 关于反射中创建类型实例的两种方法 ASP.Net应用程序的多进程模型 NET委托:一个C#睡前故事 [推荐] - [原创] Microsoft .NET策略及框架概述 ...

    Python核心编程(第二版).pdf (压缩包分2部分,第二部分)

     1.5 运行python   1.5.1 命令行上的交互式解释器  . 1.5.2 从命令行启动脚本   1.5.3 集成开发环境   1.5.4 其他的集成开发环境和执行环境   1.6 python文档   1.7 比较python(python与其他...

    Python核心编程(第二版).pdf (压缩包分2部分,第一部分)

     1.5 运行python   1.5.1 命令行上的交互式解释器  . 1.5.2 从命令行启动脚本   1.5.3 集成开发环境   1.5.4 其他的集成开发环境和执行环境   1.6 python文档   1.7 比较python(python与其他...

    Python核心编程第二版(ok)

     1.5 运行Python   1.5.1 命令行上的交互式解释器   1.5.2 从命令行启动脚本   1.5.3 集成开发环境   1.5.4 其他的集成开发环境和执行环境   1.6 Python文档   1.7 比较Python(Python与其他...

    Python核心编程第二版

     1.5 运行Python   1.5.1 命令行上的交互式解释器   1.5.2 从命令行启动脚本   1.5.3 集成开发环境   1.5.4 其他的集成开发环境和执行环境   1.6 Python文档   1.7 比较Python(Python与其他...

    vb控件开发 开发ocx

    浅谈用VB6.0编写BO程序 47 , 47.txt 巧用Visual Basic的TIMER控件 48 , 48.txt 取得控件绝对Top值 49 , 49.txt 如 何 解 决VB 中 的Grid 控 件 的 打 印 问 题 50 , 50.txt 如果自定义 MsgBox 的按钮,标题等 51 , 51...

Global site tag (gtag.js) - Google Analytics