sun jre本身的classloader主要包含三个loader,分别是
1. Bootstrap class loader->C代码 (加载%java_home%/lib/*)
2. Extensions class loader->ExtClassLoader (%java_home%/lib/ext/*)
3. System class loader->AppClassLoader (加载classpath下的类)
为什么他们会加载这些路径下面的class呢?
ExtClassLoader和AppClassLoader的构造函数可以看出
String s = System.getProperty("java.class.path");
new ExtClassLoader(s, extcl);
String s = System.getProperty("java.ext.dirs");
new AppClassLoader(s, extcl);
ExtClassLoader和AppClassLoader都继承于URLClassLoader,构造函数传递的path将来会作为加载class的路径范围
(注: ExtClassLoader和AppClassLoader不属于标准的java api,是sun.misc.Launcher的内部类,具体源码在openjdk中,在线地址为
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/misc/Launcher.java
)
那如何加载字节码class文件呢?
以AppClassLoader为例,当需要它加载A.class时,会调用其loadClass(String name, boolean resolve)方法,
此方法会通过super.loadClass(name, resolve)交由父类,最终由java.lang.ClassLoader处理,代码如下
(java.lang.ClassLoader.loadClass方法)
protected synchronized Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
// First, check if the class has already been loaded
Class c = findLoadedClass(name);
if (c == null) {
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
c = findClass(name);
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
从这段代码可以看出加载class有一个委托的模型,AppClassLoader,ExtClassLoader, Bootstrap classoader在建立初期就创建了一个所谓的父子关系(并不是继承关系),
如图
其后在加载具体class的时候会有个委托parent classloader加载,parent加载不到,再由自己加载的过程,目的就是为了安全,防止java的核心类库被修改,如果用这种模型,java.lang.String类就不能由用户自己去实现,
因为他肯定最终还是Bootstrap classoader类去加载了,因为string.class是在%java_home%/lib/*下的rt.jar中
(注:如果你一定要自己写一个java.lang.String覆盖jre自己的,你可以自己实现classloader,然后违反委托模型,这是可以做到的)
可以看到上面的java.lang.ClassLoader.loadClass方法会调用 findClass(name)去真正得到一个class对象,此方法有ClassLoader的子类,ExtClassLoader和AppClassLoader的父类URLClassLoader实现,
具体方法实现如下(去掉不影响理解的代码)
(java.lang.URLClassLoader.findClass方法)
protected Class<?> findClass(final String name) {
String path = name.replace('.', '/').concat(".class");
//ucp变量就是当初构造AppClassLoader的时候传递的路径,这里使用到
Resource res = ucp.getResource(path, false);
return defineClass(name, res, true);
}
上面会继续调用到defineClass方法
(java.lang.URLClassLoader.defineClass方法)
private Class defineClass(String name, Resource res, boolean verify)
throws IOException {
int i = name.lastIndexOf('.');
URL url = res.getCodeSourceURL();
// Now read the class bytes and define the class
ByteBuffer bb = res.getByteBuffer();
byte[] bytes = ((bb == null)? res.getBytes() : null);
// NOTE: Must read certificates AFTER reading bytes above.
CodeSigner[] signers = res.getCodeSigners();
CodeSource cs = new CodeSource(url, signers);
if (!verify) {
// Need to use reflection since methods are private in super class
Object[] args = {
name, (bb == null? ByteBuffer.wrap(bytes) : bb), cs
};
try {
return (Class) defineClassNoVerifyMethod.invoke(this, args);
} catch (IllegalAccessException iae) {
// Should never happen; fall back to the regular defineClass
}
}
return (bb != null? defineClass(name, bb, cs) :
defineClass(name, bytes, 0, bytes.length, cs));
}
上面方法会先通过stream的方式读取字节码转为byte数组,然后最终交由ClassLoader的defineClass1方法
(java.lang.ClassLoader.defineClass1方法)
private native Class defineClass1(String name, byte[] b, int off, int len,
ProtectionDomain pd, String source,
boolean verify);
上面方法是native方法,这是加载字节码的最后一步,可以想象,这必须由jvm本身来实现
以上总结:加载class首先有个委托的过程,而加载本身又是经历根据路径寻找字节码,加载字节流,讲字节流转为Class对象的过程
分享到:
相关推荐
Java中的类加载器(ClassLoader)是Java虚拟机(JVM)的一个重要组成部分,它负责将类的.class文件从文件系统或者网络中加载到内存中,并转换为对应的Class对象。类加载器的工作流程主要包括加载、验证、准备、解析...
这表明 `ClassLoaderTree` 类由 `Launcher$AppClassLoader` 加载,其父类加载器为 `Launcher$ExtClassLoader`,最终父类加载器为 `Bootstrap ClassLoader`,由于后者是系统自带且无法通过 Java 程序访问,因此返回 `...
破解java加密的rt.jar,在classloader植入破解代码,默认输出到c:/TEMP/classes/目录。使用方法:只要下载本rt.jar,然后替换掉jdk1.8.0_25\jre\lib目录下的rt.jar。然后运行你需要破解的java程序即可,如果你的java...
- **Bootstrap ClassLoader**:这是JVM自带的类加载器,用于加载JVM的核心类库,如`java.lang`包下的类。 - **Extension ClassLoader**:由`sun.misc.Launcher$ExtClassLoader`实现,负责加载`JAVA_HOME/lib/ext`...
Bootstrap ClassLoader主要负责加载JDK自带的类库,如rt.jar;Extension ClassLoader则加载Java的扩展类库,如jre/lib/ext目录下的jar文件;AppClassLoder加载用户自定义的类,即classpath路径下的类。 在源码层面...
- **内存管理**:Java 自带垃圾回收机制,但开发者仍需关注对象创建和销毁,避免内存泄漏。 6. **调试与测试** - **Junit**:Java 测试框架 JUnit 可用于编写单元测试,确保代码的正确性。 - **集成开发环境...
### Java中的ClassLoader技术及其在OSGI模块隔离中的运用 #### 一、基本概念 Java引入了虚拟机的概念,即Java虚拟机(JVM),它在硬件平台和编译程序之间添加了一层抽象层,使Java程序能够跨平台运行。Java程序...
1. Bootstrap ClassLoader:这是JVM自带的,加载Java核心库(如rt.jar)。 2. Common ClassLoader:加载`CATALINA_HOME/lib`目录下的所有JAR文件。 3. Shared ClassLoader:用于加载多个Web应用共享的类库,存在于`...
1. **Bootstrap ClassLoader**:这是JVM自带的类加载器,负责加载JVM自带的核心类库以及`$JAVA_HOME/jre/lib/ext/*.jar`目录下的扩展类库。 2. **System ClassLoader**:通常由JVM的`java.class.path`系统属性指向...
1. **Java ClassLoader原理** - Java程序在运行时,类的加载是由ClassLoader负责的。默认情况下,当类被加载后,除非应用停止,否则ClassLoader不会重新加载该类。 - Java的双亲委托模型(Parent Delegation Model...
在编译阶段,程序员需要使用 JDK 中自带的 javac.exe 命令进行 Java 程序的编译。javac.exe 是一个 Java 编译器工具/命令,可以将 Java 源文件编译生成多个.class 文件。例如, javac Java 源文件的路径。 (二)...
- **Bootstrap ClassLoader**:这是JVM自带的一个特殊类加载器,用于加载核心类库(如`rt.jar`)中的类。 - **Extension ClassLoader**:该加载器用于加载扩展类库中的类,这些类库位于`$JAVA_HOME/lib/ext`目录下。...
虽然JVM自带的ClassLoader功能强大,但在特定情况下,自定义ClassLoader有其必要性: 1. **安全性增强**:在执行不可信代码前,可以使用自定义ClassLoader进行数字签名验证,增加系统的安全性。 2. **定制化构建**...
Java SE是Java开发工具包(JDK)自带的标准API,涵盖了广泛的领域,包括面向对象编程、集合框架、网络编程、多线程、I/O流等。没有扎实的Java SE基础,就无法有效地进行Java EE或Java ME的开发。 Java类加载机制是...
支持Java代码热更新(可指定ClassLoader) 支持远程执行GC 支持远程执行JDK自带工具命令,包含但不限于jps、jstat、jstack、jinfo、jmap、jcmd等 提供客户端交互工具,支持跨进程attach和远程连接功能 支持三种服务...
在Java中,类加载由类加载器(Class Loader)完成,而类加载器分为三个层次:Bootstrap ClassLoader、Extension ClassLoader 和 Application ClassLoader。 1. **Bootstrap ClassLoader**:负责加载位于`<JAVA_HOME>\...
- **Bootstrap ClassLoader**:这是 JVM 自带的类加载器,负责加载核心类库(如 java.lang.*)。 - **Platform ClassLoader**:用于加载平台特定的扩展库。 - **App ClassLoader**:即系统的类加载器,负责加载...
这是JVM自带的类加载器,用于加载核心的类库,如`java.lang`、`java.util`等,这些类库存储在`$JAVA_HOME/jre/lib`目录下。Bootstrap ClassLoader不会从磁盘上加载任何类,而是直接读取JRE中的这些核心类库。 #### ...