静态库、动态连接库
程序编制一般需经编辑、编译、连接、加载和运行几个步骤。在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”文件;在连接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中。这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。
为了克服这个缺点可以采用动态连接库。这个时候连接器仅仅是在可执行文件中打上标志,说明需要使用哪些动态连接库;当运行程序时,加载器根据这些标志把所需的动态连接库加载到内存。
另外在当前的编程环境中,一般都提供方法让程序在运行的时候把某个特定的动态连接库加载并运行,也可以将其卸载(例如Win32的LoadLibrary()&FreeLibrary()和Posix的dlopen()&dlclose())。这个功能被广泛地用于在程序运行时刻更新某些功能模块或者是程序外观。
What is ClassLoader?
与普通程序不同的是,Java程序(class文件)并不是本地的可执行程序。当运行Java程序时,首先运行JVM(Java虚拟机),然后再把Java class加载到JVM里头运行,负责加载Java class的这部分就叫做Class Loader。
JVM本身包含了一个ClassLoader称为Bootstrap ClassLoader,和JVM一样,Bootstrap ClassLoader是用本地代码实现的,它负责加载核心Java Class(即所有java.*开头的类)。另外JVM还会提供两个ClassLoader,它们都是用Java语言编写的,由Bootstrap ClassLoader加载;其中Extension ClassLoader负责加载扩展的Java class(例如所有javax.*开头的类和存放在JRE的ext目录下的类),Application ClassLoader负责加载应用程序自身的类。
当运行一个程序的时候,JVM启动,运行bootstrap classloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。
注: 学ClassLoader看OSGI
When to load the class?
什么时候JVM会使用ClassLoader加载一个类呢?当你使用java去执行一个类,JVM使用Application ClassLoader加载这个类;然后如果类A引用了类B,不管是直接引用还是用Class.forName()引用,JVM就会找到加载类A的ClassLoader,并用这个ClassLoader来加载类B。JVM按照运行时的有效执行语句,来决定是否需要装载新类,从而装载尽可能少的类,这一点和编译类是不相同的。
Why use your own ClassLoader?
似乎JVM自身的ClassLoader已经足够了,为什么我们还需要创建自己的ClassLoader呢?
因为JVM自带的ClassLoader只是懂得从本地文件系统加载标准的java class文件,如果编写你自己的ClassLoader,你可以做到:
1)在执行非置信代码之前,自动验证数字签名
2)动态地创建符合用户特定需要的定制化构建类
3)从特定的场所取得java class,例如数据库中
4) 等等
事实上当使用Applet的时候,就用到了特定的ClassLoader,因为这时需要从网络上加载java class,并且要检查相关的安全信息。
目前的应用服务器大都使用了ClassLoader技术,即使你不需要创建自己的ClassLoader,了解其原理也有助于更好地部署自己的应用。
ClassLoader Tree & Delegation Model
当你决定创建你自己的ClassLoader时,需要继承java.lang.ClassLoader或者它的子类。在实例化每个ClassLoader对象时,需要指定一个父对象;如果没有指定的话,系统自动指定ClassLoader.getSystemClassLoader()为父对象。
所以当创建自己的Class Loader时,只需要重载findClass()这个方法。
Unloading? Reloading?
当一个java class被加载到JVM之后,它有没有可能被卸载呢?我们知道Win32有FreeLibrary()函数,Posix有dlclose()函数可以被调用来卸载指定的动态连接库,但是Java并没有提供一个UnloadClass()的方法来卸载指定的类。
在Java中,java class的卸载仅仅是一种对系统的优化,有助于减少应用对内存的占用。既然是一种优化方法,那么就完全是JVM自行决定如何实现,对Java开发人员来说是完全透明的。
在什么时候一个java class/interface会被卸载呢?Sun公司的原话是这么说的:"class or interface may be unloaded if and only if its class loader is unreachable. Classes loaded by the bootstrap loader may not be unloaded."
事实上我们关心的不是如何卸载类的,我们关心的是如何更新已经被加载了的类从而更新应用的功能。JSP则是一个非常典型的例子,如果一个JSP文件被更改了,应用服务器则需要把更改后的JSP重新编译,然后加载新生成的类来响应后继的请求。
其实一个已经加载的类是无法被更新的,如果你试图用同一个ClassLoader再次加载同一个类,就会得到异常(java.lang.LinkageError: duplicate class definition),我们只能够重新创建一个新的ClassLoader实例来再次加载新类。至于原来已经加载的类,开发人员不必去管它,因为它可能还有实例正在被使用,只要相关的实例都被内存回收了,那么JVM就会在适当的时候把不会再使用的类卸载。
使用线程上下文类加载器, 可以在执行线程中, 抛弃双亲委派加载链模式, 使用线程上下文里的类加载器加载类.
典型的例子有, 通过线程上下文来加载第三方库jndi实现, 而不依赖于双亲委派.
大部分java app服务器(jboss, tomcat..)也是采用contextClassLoader来处理web服务。
当然, 好东西都有利弊. 使用线程上下文加载类, 也要注意, 保证多根需要通信的线程间的类加载器应该是同一个, 防止因为不同的类加载器, 导致类型转换异常(ClassCastException).
参考资料及图片来源——Understanding J2EE Application Server Class Loading Architectures
http://www.jdon.com/jivejdon/thread/15456.html
http://gceclub.sun.com.cn/yuanchuang/week-9/classloader.html
分享到:
相关推荐
2. 创建自定义ClassLoader:掌握如何编写自己的ClassLoader子类,实现自定义的加载策略。 3. 整合自定义ClassLoader:了解如何将自定义的ClassLoader集成到Java应用程序中,替换或扩展默认的加载行为。 4. 考虑Java ...
WebLogic采用"parent first"策略,即父ClassLoader先于子ClassLoader尝试加载类。这样的设计是为了确保全局库(如JDBC驱动)优先从系统路径加载,保证了库的一致性。然而,对于Web应用程序,WebLogic创建了一个独立...
在`findClass`中,我们可以实现自己的类查找策略,而在`loadClass`中,我们需要调用`defineClass`方法将字节码转换为Class对象。 三、自定义加载路径 默认情况下,Classloader从JAR文件或当前目录(CLASSPATH)...
三、ClassLoader的装载策略 从Java 1.2版本开始,引入了双亲委派模型(Delegation Model)。在该模型下,当一个ClassLoader收到加载类的请求时,它首先会委托父加载器去尝试加载,只有当父加载器无法加载时,当前...
深入理解ClassLoader的工作原理对于优化应用性能、解决类加载问题以及实现自定义加载策略至关重要。 首先,JVM启动时,会构建一个类加载器的层次结构,主要包括三个基本类加载器: 1. Bootstrap ClassLoader:引导...
ClassLoader的扩展性体现在,我们可以通过继承ClassLoader并重写其方法,实现自己的类加载策略。例如,我们可以创建一个网络ClassLoader,从远程服务器动态加载类,实现按需加载,减少内存占用。 总的来说,理解...
在Java编程语言中,类加载器(ClassLoader)是运行时环境的核心组成部分,它负责将类的字节码从各种来源(如JAR文件、网络、内存等)加载到Java虚拟机(JVM)中,使得程序能够运行。本文将深入探讨“使用classloader...
为了防止这种情况,开发者可以采用以下策略: 1. 使用混淆工具,如ProGuard或ZapGoat,它们能重命名类、方法和变量,使其变得难以阅读和理解。 2. 实现自定义的类加载器,添加额外的检查逻辑,比如在加载类时进行...
自定义`ClassLoader`能够帮助我们实现特定的加载策略,比如隔离不同版本的库或动态加载类。 `ClassLoader`的工作原理主要是通过读取`.class`文件并将其转换为`Class`对象。默认情况下,Java使用`Bootstrap ...
验证阶段确保加载的类符合Java语法规则和安全策略。准备阶段则为类的静态变量分配内存并初始化为默认值。之后,类的初始化(初始化阶段)才会进行,包括执行静态初始化块和设置静态变量。 ClassLoader的层次结构...
应合理设计缓存策略,例如使用弱引用或软引用,允许垃圾收集器在内存紧张时回收。 5. 文件句柄或网络连接:类加载器可能打开文件或保持网络连接,如果在加载完成后未关闭,也会导致资源泄露。务必在类加载器不再...
### Java ClassLoader原理详解 #### 摘要 本文探讨了Java虚拟机(JVM)中的一个重要特性:动态类加载(Dynamic Class Loading)。这一机制为Java平台提供了强大的能力,允许在运行时安装软件组件,例如从网络下载...
- **双亲委派模型**:这是一种新的类加载策略,可以避免类加载器之间的循环依赖问题。 - **模块化支持**:Java 2引入了更强大的模块化支持,这有助于更好地组织和管理大型应用程序中的类。 - **安全性增强**:为了...
5. **Parent First / Child First策略**:Tomcat的ClassLoader加载策略有两种,一种是"parent first",另一种是"child first"。默认情况下,Tomcat采用"parent first"策略,即Webapp ClassLoader先尝试让上级Loader...
通过这些例子,我们可以学习到如何覆盖`loadClass()`方法,改变默认的类查找策略。例如,可以实现一个只加载指定目录下类的类加载器,或者实现一个能加载加密或压缩格式的类文件的类加载器。 此外,"classloader-...
例如,通过自定义`ClassLoader`,我们可以覆盖默认的加载逻辑,实现特定的类查找策略。 **类的卸载**是Java中比较复杂的话题,因为JVM的垃圾收集机制通常不处理类的卸载。然而,如果`ClassLoader`能够被垃圾收集,...
1. `classloader`:包含了自定义的`java.lang.ClassLoader`扩展,但没有特定的类加载策略。这个子项目主要关注类加载的基础功能,即从何处加载类以及如何加载。 2. `classloading`:这是Microcontainer依赖注入机制...
Java中的类加载器(ClassLoader)是Java虚拟机(JVM)的一个重要组成部分,它负责将类的.class文件从文件系统或者网络...理解类加载机制对于解决类冲突、优化应用性能以及实现特定的加载策略(如热部署)具有重要意义。
优化类加载策略,比如延迟加载、缓存等,可以提升Web应用的性能。 通过分析`web_classloader_test`,我们可以学习到如何理解和调试Web应用的类加载问题,以及如何利用类加载器的特性来实现特定的功能。这个示例对于...
这里的“简单”通常意味着这个自定义`ClassLoader`只实现了基本的功能,如加载特定位置的字节码文件,而不涉及复杂的类加载策略或安全机制。自定义`ClassLoader`是扩展Java应用程序的一种方式,它可以让我们在运行时...