- 浏览: 33160 次
- 性别:
- 来自: 杭州
-
文章分类
最新评论
-
xin_jing:
帮下忙,我想看下你的Hessian.php,我是php新手 ...
使用hessian php与Java通信 -
youjianbo_han_87:
最后一点很好啊。
使用hessian php与Java通信 -
ilovejavaforever:
遗漏了很多关键内容.....
全文搜索的基本原理
目录
一、ClassLoader 类加载器介绍
二、ClassLoader 类加载器的工作机制分析
三、WebAppClassLoader 模拟实现一个简单的Web应用类加载器
一、ClassLoader 类加载器介绍
这里使用的JDK是sun的jdk1.6.0_18版本,重在阐述原理和具体版本没有多大的关系。
JVM 中预定义了3种类型的类加载器:启动类加载器、扩展类加载器、系统类加载器(也叫应用类加载器)。当一个 JVM 虚拟机启动后,它默认使用这3种。
1. 启动类加载器(bootstrap)是虚拟机实现的一部分,它负责将sun.boot.class.path路径中的Java API类加载到内存中。由于启动类加载器是由虚拟机的本地代码实现,因而开发者无法在Java程序中直接获取启动类加载器的引用。
2. 扩展类加载器(extension)是由sun.misc.Launcher$ExtClassLoader实现的,它负责将java.ext.dirs路径中的Java类加载到内存中,在Java程序中可以直接引用。
3. 系统类加载器(system)是由sun.misc.Launcher$AppClassLoader实现的,它负责将java.class.path路径中的Java类加载到内存中,在Java程序中可以直接引用。
二、ClassLoader 类加载器的工作机制分析
JVM 中默认采用父子关系的类加载机制,通过启动类加载器、扩展类加载器、系统类加载器依次从上而下形成父子关系。
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
1.Invoke findLoadedClass(String) to check if the class has already been loaded.
2.Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
3.Invoke the findClass(String) method to find the class.
If the class was found using the above steps, and the resolve flag is true, this method will then invoke the resolveClass(Class) method on the resulting Class object.
Subclasses of ClassLoader are encouraged to override findClass(String), rather than this method.
JVM“扩展类加载器”与“系统类加载器”类型层次图
通过上面两图可以看出sun.misc.Launcher$ExtClassLoader 与 sun.misc.Launcher$AppClassLoader 均继承 java.lang.ClassLoader 抽象类
阅读java.net.URLClassLoader、java.security.SecureClassLoader、sun.misc.Launcher$ExtClassLoader、sun.misc.Launcher$AppClassLoader 的源码,可以看出它们都没有覆写 java.lang.ClassLoader 中的默认加载规则 loadClass(String,boolean) 方法,这样就可以通过 loadClass 方法的代码分析出,虚拟机默认采用的父子加载机制到底是咋样的。
父子加载机制说明:假设在某个特定的类加载器接到类加载请求时
三、WebAppClassLoader 模拟实现一个简单的Web应用类加载器
这个简单的模拟需要在eclipse工作空间中建立2个项目,一个java项目,一个web项目
Java项目:就包含一个WebAppClassLoader.java
web项目:包含MockResponse.java、MockServlet.java、test.jar(这个jar包就包含一个WebAppClassLoader.java文件)
------------- bootstrap: sun.boot.class.path -------------
D:\Program Files\Java\jdk1.6.0_18\jre\lib\resources.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\rt.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\sunrsasign.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\jsse.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\jce.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\charsets.jar
D:\Program Files\Java\jdk1.6.0_18\jre\classes
------------- extension: java.ext.dirs -------------
D:\Program Files\Java\jdk1.6.0_18\jre\lib\ext
C:\Windows\Sun\Java\lib\ext
------------- system: java.class.path -------------
D:\test-work\java\classes
D:\Program Files\eclipse\plugins\org.junit4_4.5.0.v20090824\junit.jar
D:\Program Files\eclipse\plugins\org.hamcrest.core_1.1.0.v20090501071000.jar
sun.misc.Launcher
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
java.lang.String
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
java.lang.Integer
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
int
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
java.util.ArrayList
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
test.classloader.WebAppClassLoader
类加载器层次结构依次由子到父
ClassLoader: sun.misc.Launcher$AppClassLoader@16f0472
ClassLoader: sun.misc.Launcher$ExtClassLoader@18d107f
test.classloader.MockServlet
类加载器层次结构依次由子到父
ClassLoader: java.net.URLClassLoader@12f0999
ClassLoader: sun.misc.Launcher$AppClassLoader@16f0472
ClassLoader: sun.misc.Launcher$ExtClassLoader@18d107f
test.classloader.MockResponse
类加载器层次结构依次由子到父
ClassLoader: java.net.URLClassLoader@12f0999
ClassLoader: sun.misc.Launcher$AppClassLoader@16f0472
ClassLoader: sun.misc.Launcher$ExtClassLoader@18d107f
hello world
测试结束
由程序输出可以到看到 java.lang.String、Integer 等类都是由“启动类加载器”所加载的,在Java程序中无法获得它的引用
WebAppClassLoader 是由“系统类加载器sun.misc.Launcher$AppClassLoader”所加载
MockServlet 与 MockResponse 是由 WebAppClassLoader 所加载
一、ClassLoader 类加载器介绍
二、ClassLoader 类加载器的工作机制分析
三、WebAppClassLoader 模拟实现一个简单的Web应用类加载器
一、ClassLoader 类加载器介绍
这里使用的JDK是sun的jdk1.6.0_18版本,重在阐述原理和具体版本没有多大的关系。
JVM 中预定义了3种类型的类加载器:启动类加载器、扩展类加载器、系统类加载器(也叫应用类加载器)。当一个 JVM 虚拟机启动后,它默认使用这3种。
1. 启动类加载器(bootstrap)是虚拟机实现的一部分,它负责将sun.boot.class.path路径中的Java API类加载到内存中。由于启动类加载器是由虚拟机的本地代码实现,因而开发者无法在Java程序中直接获取启动类加载器的引用。
2. 扩展类加载器(extension)是由sun.misc.Launcher$ExtClassLoader实现的,它负责将java.ext.dirs路径中的Java类加载到内存中,在Java程序中可以直接引用。
3. 系统类加载器(system)是由sun.misc.Launcher$AppClassLoader实现的,它负责将java.class.path路径中的Java类加载到内存中,在Java程序中可以直接引用。
二、ClassLoader 类加载器的工作机制分析
JVM 中默认采用父子关系的类加载机制,通过启动类加载器、扩展类加载器、系统类加载器依次从上而下形成父子关系。
引用JDK API文档 写道
Loads the class with the specified binary name. The default implementation of this method searches for classes in the following order:
1.Invoke findLoadedClass(String) to check if the class has already been loaded.
2.Invoke the loadClass method on the parent class loader. If the parent is null the class loader built-in to the virtual machine is used, instead.
3.Invoke the findClass(String) method to find the class.
If the class was found using the above steps, and the resolve flag is true, this method will then invoke the resolveClass(Class) method on the resulting Class object.
Subclasses of ClassLoader are encouraged to override findClass(String), rather than this method.
JVM“扩展类加载器”与“系统类加载器”类型层次图


通过上面两图可以看出sun.misc.Launcher$ExtClassLoader 与 sun.misc.Launcher$AppClassLoader 均继承 java.lang.ClassLoader 抽象类
阅读java.net.URLClassLoader、java.security.SecureClassLoader、sun.misc.Launcher$ExtClassLoader、sun.misc.Launcher$AppClassLoader 的源码,可以看出它们都没有覆写 java.lang.ClassLoader 中的默认加载规则 loadClass(String,boolean) 方法,这样就可以通过 loadClass 方法的代码分析出,虚拟机默认采用的父子加载机制到底是咋样的。
父子加载机制说明:假设在某个特定的类加载器接到类加载请求时
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { //首先查找cache中是否已有对应的Class Class c = findLoadedClass(name); if (c == null) { try { if (parent != null) { //如果没有再委托给它的父类加载器,依次递归 c = parent.loadClass(name, false); } else { //父类加载器不存在时使用“启动类加载器” c = findBootstrapClass0(name); } } catch (ClassNotFoundException e) { //只有父类或“启动类加载器”都无法完成加载时,才自己去加载。 c = findClass(name); } } if (resolve) { //连接处理,为类变量分配内存初始化默认值、解析符号引用 resolveClass(c); } return c; }
三、WebAppClassLoader 模拟实现一个简单的Web应用类加载器
这个简单的模拟需要在eclipse工作空间中建立2个项目,一个java项目,一个web项目
Java项目:就包含一个WebAppClassLoader.java
package test.classloader; import java.io.File; import java.io.FilenameFilter; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; /** * 模拟实现一个简单的Web应用类加载器 * @author linliuwei * @create 2010-5-7 */ public class WebAppClassLoader { private URLClassLoader myClassLoader = null; /** * 如: new WebAppClassLoader("D:/workspace/webapp/WebRoot") * @param webroot web应用的根目录 */ public WebAppClassLoader(String webroot) { URL[] urls = null; try { urls = getJARURLs(webroot); } catch (MalformedURLException e) { System.out.println(e.getMessage()); } myClassLoader = new URLClassLoader(urls); } public Class<?> loadClass(String className) throws ClassNotFoundException { return myClassLoader.loadClass(className); } /** * 获得web应用下的所有classpath的URL * * <pre> * WEB-INF\classes 目录 * WEB-INF\lib 下的所有jar文件 * </pre> * @param webroot * @return * @throws MalformedURLException */ private URL[] getJARURLs(String webroot) throws MalformedURLException { if (!webroot.endsWith(File.separator)) { webroot += File.separator; } // web应用中的WEB-INF\classes File classesDir = new File(webroot + File.separator + "WEB-INF" + File.separator + "classes"); // web应用中的WEB-INF\lib File libDir = new File(webroot + File.separator + "WEB-INF" + File.separator + "lib"); // 找出WEB-INF\lib目录下所有的jar文件 File[] jarFiles = null; if (libDir.isDirectory()) { // 文件名过滤器,只允许.jar文件 jarFiles = libDir.listFiles(new FilenameFilter() { public boolean accept(File dir, String name) { // jar文件所在目录必须是一个文件夹 if (dir.isDirectory() && name.endsWith(".jar")) { return true; } return false; } }); } int jarCount = null == jarFiles ? 0 : jarFiles.length; URL[] urls = new URL[1 + jarCount]; urls[0] = classesDir.toURI().toURL();// WEB-INF\classes for (int i = 0; i < jarCount; i++) { // WEB-INF\lib下的所有jar文件 urls[i + 1] = jarFiles[i].toURI().toURL(); } return urls; } private static void printClassLoader(ClassLoader classLoader) { if (classLoader != null) { System.out.println("\tClassLoader: " + classLoader); if (classLoader.getParent() != null) { printClassLoader(classLoader.getParent()); } } else { System.out.println("\t此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用"); } } // 打印类加载器的父子层次结构 public static void printClassLoaderHierarchy(Class<?> clazz) { System.out.println(clazz.getName()); if (clazz.getClassLoader() != null) { System.out.println("\t类加载器层次结构依次由子到父"); } printClassLoader(clazz.getClassLoader()); System.out.println(); } public static void printClassPath() { String separator = System.getProperty("path.separator"); System.out.println("------------- bootstrap: sun.boot.class.path -------------"); System.out.println(System.getProperty("sun.boot.class.path").replaceAll(separator, "\n")); System.out.println(); System.out.println("------------- extension: java.ext.dirs -------------"); System.out.println(System.getProperty("java.ext.dirs").replaceAll(separator, "\n")); System.out.println(); System.out.println("------------- system: java.class.path -------------"); System.out.println(System.getProperty("java.class.path").replaceAll(separator, "\n")); System.out.println(); } public static void main(String[] mainArgs) { try { printClassPath(); printClassLoaderHierarchy(sun.misc.Launcher.class); printClassLoaderHierarchy(String.class); printClassLoaderHierarchy(Integer.class); printClassLoaderHierarchy(int.class); printClassLoaderHierarchy(ArrayList.class); // 创建web应用类加载器 WebAppClassLoader classLoader = new WebAppClassLoader("D:/test-work/webapp/WebRoot"); printClassLoaderHierarchy(classLoader.getClass()); Class<?> mockServlet = classLoader.loadClass("test.classloader.MockServlet"); printClassLoaderHierarchy(mockServlet); // 用反射调用main方法 String[] args = new String[] {}; mockServlet.getMethod("main", args.getClass()).invoke(null, (Object) args); System.out.println("测试结束"); } catch (Exception e) { e.printStackTrace(); } } }
web项目:包含MockResponse.java、MockServlet.java、test.jar(这个jar包就包含一个WebAppClassLoader.java文件)
package test.classloader; public class MockResponse { public void print() { System.out.println("hello world"); } } package test.classloader; public class MockServlet { public static void main(String[] args) { MockResponse response = new MockResponse(); WebAppClassLoader.printClassLoaderHierarchy(response.getClass()); response.print(); } }
WebAppClassLoader中的Main方法输出 写道
------------- bootstrap: sun.boot.class.path -------------
D:\Program Files\Java\jdk1.6.0_18\jre\lib\resources.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\rt.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\sunrsasign.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\jsse.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\jce.jar
D:\Program Files\Java\jdk1.6.0_18\jre\lib\charsets.jar
D:\Program Files\Java\jdk1.6.0_18\jre\classes
------------- extension: java.ext.dirs -------------
D:\Program Files\Java\jdk1.6.0_18\jre\lib\ext
C:\Windows\Sun\Java\lib\ext
------------- system: java.class.path -------------
D:\test-work\java\classes
D:\Program Files\eclipse\plugins\org.junit4_4.5.0.v20090824\junit.jar
D:\Program Files\eclipse\plugins\org.hamcrest.core_1.1.0.v20090501071000.jar
sun.misc.Launcher
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
java.lang.String
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
java.lang.Integer
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
int
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
java.util.ArrayList
此类的类加载器为“启动类加载器”,它是由虚拟机的本地代码实现,在Java程序中无法引用
test.classloader.WebAppClassLoader
类加载器层次结构依次由子到父
ClassLoader: sun.misc.Launcher$AppClassLoader@16f0472
ClassLoader: sun.misc.Launcher$ExtClassLoader@18d107f
test.classloader.MockServlet
类加载器层次结构依次由子到父
ClassLoader: java.net.URLClassLoader@12f0999
ClassLoader: sun.misc.Launcher$AppClassLoader@16f0472
ClassLoader: sun.misc.Launcher$ExtClassLoader@18d107f
test.classloader.MockResponse
类加载器层次结构依次由子到父
ClassLoader: java.net.URLClassLoader@12f0999
ClassLoader: sun.misc.Launcher$AppClassLoader@16f0472
ClassLoader: sun.misc.Launcher$ExtClassLoader@18d107f
hello world
测试结束
由程序输出可以到看到 java.lang.String、Integer 等类都是由“启动类加载器”所加载的,在Java程序中无法获得它的引用
WebAppClassLoader 是由“系统类加载器sun.misc.Launcher$AppClassLoader”所加载
MockServlet 与 MockResponse 是由 WebAppClassLoader 所加载
发表评论
-
使用hessian php与Java通信
2010-06-13 15:41 13180去年2009-07-13在百度空间 ... -
一些Java术语
2010-06-13 14:36 0JCP(Java Community Process) Ja ... -
一个从content中提取email的小方法
2010-06-12 20:07 1124这两天搞了一个时间程序,就是定时每天将一个地方的数据导出到另一 ... -
Sun Java HotSpot™ Virtual Machine内存模型与垃圾回收
2010-06-12 05:27 1755先前公司的一个J2EE应用 ... -
深入Java虚拟机读书笔记
2010-05-30 19:20 1383深入Java虚拟机一书读书 ... -
OSGI原理与最佳实践读书笔记
2010-05-16 17:38 0OSGI原理与最佳实践 作者:淘宝网平台架构部林昊 OSGI ... -
Java Classloader 类加载篇(2)
2010-05-15 22:55 12321. ContextClassLoader 线程上 ... -
Java Basic I/O
2010-04-15 00:15 0学习资料与书籍 1.Java与模式 作者:阎宏博士 两个 ...
相关推荐
双亲委派模型使得系统类(如java.*开头的类)由Bootstrap ClassLoader加载,而用户自定义类由应用程序类加载器(AppClassLoader)加载。这避免了类的冲突,保持了系统类库的稳定性。但有时我们可能需要打破这种模型...
Java的ClassLoader类加载器机制 在 Java 虚拟机(JVM)中,类加载器(ClassLoader)扮演着非常重要的角色。类加载器负责加载 Java 类,包括核心类和用户自定义类。在 JVM 运行过程中,类加载器会形成一个层次结构,...
1. Bootstrap ClassLoader:这是最基础的类加载器,由JVM本身实现,负责加载JRE的`<JAVA_HOME>/lib`目录下的核心类库,或者被`-Xbootclasspath`参数指定的路径中的类。 2. Extension ClassLoader:扩展类加载器,...
1. **引导类加载器(Bootstrap ClassLoader)**:这是最基础的类加载器,负责加载Java的核心库类,如`java.lang`包下的类。 2. **扩展类加载器(Extension ClassLoader)**:它负责加载位于`-Djava.ext.dirs`系统...
接着,Extension ClassLoader加载扩展类库,然后是App ClassLoader加载应用程序的类路径下的类。每个ClassLoader都有其父ClassLoader,它们形成了一个层次结构,子ClassLoader可以委托父ClassLoader去加载类,避免了...
扩展类加载器是一个Java类,它在运行时被Bootstrap ClassLoader加载,并且它同样会加载扩展API中的类。 3. Application ClassLoader(应用程序类加载器):也被称为System ClassLoader(系统类加载器),它负责加载...
1. **引导类加载器(Bootstrap ClassLoader)**:这是最基础的类加载器,由JVM本身实现,主要负责加载JDK核心库,如rt.jar中的类,这些类通常位于JRE的lib目录下。 2. **扩展类加载器(Extension ClassLoader)**:由...
【图解版】深入分析ClassLoader类加载工作机制,从原理到JVM的装载过程,详情分析了ClassLoader加载类以及自定义类加载器的过程,不可用于商业用途,如有版权问题,请联系删除!
类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的。Java ...
1. **自定义ClassLoader**:Java允许我们创建自定义的ClassLoader,这通常用于实现动态加载类的需求。自定义ClassLoader需要重写`findClass()`或`loadClass()`方法。`loadClass()`方法是类加载的入口,它会调用`find...
1. **Bootstrap Class Loader(启动类加载器)**:该类加载器使用C++编写,是JVM自身的一部分,用于加载位于`JAVA_HOME/jre/lib/rt.jar`中的类库,以及其他一些核心类库(如`java.lang.*`等)。Bootstrap Class ...
- **扩展类加载器(Extension ClassLoader)**:负责加载Java扩展目录(`<JAVA_HOME>/jre/lib/ext`)下的类库。 - **应用程序类加载器(Application ClassLoader)**:也称为系统类加载器,负责加载用户类路径...
Java中ClassLoader类加载学习总结 ClassLoader类加载是Java语言的一种创新,目的是为了将类的加载过程与虚拟机解耦,达到”通过类的全限定名来获取描述此类的二进制字节流“的目的。类加载器的基本模型就是双亲委派...
1. **启动类加载器(Bootstrap ClassLoader)** - **实现语言**:C++ - **位置**:属于JVM的一部分 - **作用**:加载JVM自身工作需要的类,如`rt.jar`等核心类库。 - **特点**:无法被Java程序直接引用。 2. **...
Java类加载器分为三种主要类型:引导类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)和应用程序类加载器(Application ClassLoader,也称为系统类加载器)。它们共同工作,确保了Java...
在Java中,类加载器主要分为三个层次:Bootstrap ClassLoader、Extension ClassLoader和AppClassLoader。Bootstrap ClassLoader负责加载JDK的核心库,如rt.jar;Extension ClassLoader则加载JRE扩展目录下的jar文件...
ClassLoader 是 Java 中的一个抽象类,它的主要作用是加载 Class 文件到 JVM 中。ClassLoader 使用了双亲委托模式进行类加载,每一个自定义的 ClassLoader 都必须继承 ClassLoader 这个抽象类,而每个 ClassLoader ...
Java ClassLoader是一个核心的Java运行时组件,负责加载类到Java虚拟机(JVM)中。它是Java平台的独特特性,因为它允许动态加载类,增强了软件的可扩展性和灵活性。这篇博文(虽然链接不可用)可能深入探讨了...
类加载器(`ClassLoader`)负责将编译后的`.class`文件加载到Java虚拟机(JVM)中执行,而类路径(`ClassPath`)则是指明了这些`.class`文件的位置。本文主要围绕Java类加载器和类路径展开讨论,以加深对Java运行时...
例如,`MemoryClassLoader.java`可能就是一个自定义类加载器的实现,它可以在内存中动态加载或更新类。 **JarinJAR**是一种打包技术,它可以将多个JAR文件打包成一个大的JAR文件。在热加载场景下,JarinJAR使得在...