这是一篇较早时候写的文章,最近在J道看到一个与classloader有关的讨论,于是重新翻出来。
静态库、动态连接库
程序编制一般需经编辑、编译、连接、加载和运行几个步骤。在我们的应用中,有一些公共代码是需要反复使用,就把这些代码编译为“库”文件;在连接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中。这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。
为了克服这个缺点可以采用动态连接库。这个时候连接器仅仅是在可执行文件中打上标志,说明需要使用哪些动态连接库;当运行程序时,加载器根据这些标志把所需的动态连接库加载到内存。
另外在当前的编程环境中,一般都提供方法让程序在运行的时候把某个特定的动态连接库加载并运行,也可以将其卸载(例如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负责加载应用程序自身的类。
When to load the class?
什么时候JVM会使用ClassLoader加载一个类呢?当你使用java去执行一个类,JVM使用Application ClassLoader加载这个类;然后如果类A引用了类B,不管是直接引用还是用Class.forName()引用,JVM就会找到加载类A的ClassLoader,并用这个ClassLoader来加载类B。
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()为父对象。如下图:
在Java 1.2后,java class的加载采用所谓的委托模式(Delegation Modle),当调用一个ClassLoader.loadClass()加载一个类的时候,将遵循以下的步骤:
1)检查这个类是否已经被加载进来了?
2)如果还没有加载,调用父对象加载该类
3)如果父对象无法加载,调用本对象的findClass()取得这个类。
所以当创建自己的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就会在适当的时候把不会再使用的类卸载。
|
相关推荐
4. 考虑Java 2版本的兼容性:学习如何修改你的ClassLoader以适应Java 2及以上版本的特性,比如支持Service Provider Interface (SPI)。 在深入学习之前,你需要理解类的生命周期,以及类加载、链接和初始化的概念。...
本篇文章将深入探讨Java ClassLoader的内部工作,并通过一个具体的实例来展示如何定制自己的ClassLoader。 首先,我们来看ClassLoader的基本工作流程。当JVM启动时,它会有一个初始的Bootstrap ClassLoader,用于...
### Java虚拟机中ClassLoader概述与双亲委托机制详解 #### 一、ClassLoader概念与作用 在Java编程语言中,`ClassLoader`是一个非常重要的组件,它负责加载程序运行所需的类文件到Java虚拟机(JVM)中。`ClassLoader`...
2. Extension ClassLoader:加载JDK扩展目录(如$JAVA_HOME/jre/lib/ext)中的类。 3. System ClassLoader(也称为AppClassLoader):加载`CLASSPATH`环境变量指定的类,以及应用主类路径(class path)上的类。 4. ...
在Java中,Classloader是加载类的关键组件,它负责查找、加载和初始化字节码文件。自定义Classloader允许开发者根据特定需求定制类的加载逻辑,例如加密类文件、隔离不同版本的库或者动态加载代码。本文将深入探讨...
2. **双亲委派模型** 这是一种为了防止类的重复加载和保证类加载的安全性而设计的机制。类加载请求会逐级向上委托,直到找到对应的类或者返回给最初发起请求的类加载器。 3. **ClassLoader的工作流程** - 加载:...
2. **验证**:验证是确保加载的类符合Java语言规范,不会破坏JVM的安全性。它检查字节码的格式、数据流和操作符计算、类和字段的访问控制等。 3. **准备**:在准备阶段,JVM为类的静态变量分配内存,并将其初始化为...
2. OSGi的ClassLoader支持动态加载和卸载bundle,当bundle被激活或停用时,对应的类加载器可以按需加载或释放类,提高了系统的灵活性和可维护性。 3. OSGi的ClassLoader还支持类的重用,如果两个bundle引用了相同的...
首先,ClassLoader可以分为三种基本类型:Bootstrap ClassLoader、Extension ClassLoader和Application ClassLoader。Bootstrap ClassLoader是JVM启动时的第一个ClassLoader,负责加载JDK的`<JAVA_HOME>\lib`目录下...
2. Extension ClassLoader:扩展类加载器。其主要任务是加载JRE的扩展目录下的JAR包,如JAVA_HOME/jre/lib/ext目录或由java.ext.dirs系统属性指定的路径。这种方式允许开发者添加JVM扩展功能,而无需修改核心类库。...
`附录A.Java 2 SDK版原始码概观.pdf`可能提供了Java 2 SDK源码的概述,这对于理解ClassLoader的工作方式非常有帮助,因为你可以看到其内部的实现细节。 `CH_00-导读.pdf`则可能是整个系列的引导章节,介绍了接下来...
2. 对`loadClass()` 和 `findClass()` 的覆写,实现自定义加载逻辑。 3. 文件I/O操作,读取并加载指定目录下的.class文件。 4. 使用`Class.forName()` 或 `Class.getDeclaredMethods()`等反射API来动态调用加载的类...
2. **加载类**:找到`.class`文件后,ClassLoader将其读入内存,并创建一个Class对象。这个过程可能涉及字节码验证,确保类的安全性。 3. **链接**:链接阶段包括三个子步骤:验证、准备和解析。验证确保字节码符合...
2. Extension ClassLoader:扩展类加载器,负责加载JRE的扩展目录(jre/lib/ext目录下的jar文件)。 3. AppClassLoade:应用程序类加载器,也叫系统类加载器,负责加载用户类路径(classpath)上的类。 在Java中,...
2. 类加载过程 类加载的过程通常分为三个阶段:加载、验证和准备、解析和初始化。 - 加载:查找并加载类的二进制数据。数据可能来自JAR文件、网络或自定义的加载源。 - 验证:确保类文件的字节码符合Java语法规则,...
破解java加密的ClassLoader.java,在classloader植入破解代码
2. **Extension ClassLoader**:扩展类加载器,负责加载`<JAVA_HOME>\lib\ext`目录中的类库,或者是由`java.ext.dirs`系统变量所指定的目录下的类库。 3. **Application ClassLoader**:应用程序类加载器,也称为...