java文件被编译为class文件,成为jvm机器码。jvm通过classloader将class的字节流加载,解析后变为class类。
-
Bootstrap ClassLoader/启动类加载器
主要负责jdk_home/lib目录下的核心 api 或 -Xbootclasspath 选项指定的jar包装入工作。
-
Extension ClassLoader/扩展类加载器
主要负责jdk_home/lib/ext目录下的jar包或 -Djava.ext.dirs 指定目录下的jar包装入工作。
-
System ClassLoader/系统类加载器
主要负责java -classpath/-Djava.class.path所指的目录下的类与jar包装入工作。
-
User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。
每个时刻,当前类有三种加载器可选择:
系统类加载器, 通过ClassLoader.getSystemClassLoader()
当前类加载器, 加载当前类的加载器。 Class.forName()会隐式调用当前类的加载器加载
当前线程类加载器, 通过Thread.getCurrentThread().getContextClassLoader()获取
加载classloader类的当前类所在的加载器,将会变成classloader的父加载器。
类加载采用双亲代理机制,加载类时,首先代理到父加载器,查找类的顺序变成从根加载器往叶子加载器向下寻找。好处是防止自定义包中实现String类。
每个加载器维护自身的名字空间,父加载器对子加载器可见,反之不可逆。jvm认定一个类,根据类名+加载器。
因为jdk中包含一些API接口类,这些类使用启动类加载器。而其接口实现类在第三方jar包中,采用系统加载类,会导致两边的类无法互相可见,最终导致ClassNotFound异常。解决方法是线程上下文加载器。
java动态载入class的两种方式:
1) implicit隐式,即利用实例化才载入的特性来动态载入class
2) explicit显式方式,又分两种方式:
java.lang.Class的forName()方法
java.lang.ClassLoader的loadClass()方法
static块在什么时候执行?
1)当调用forName(String)载入class时执行,如果调用ClassLoader.loadClass并不会执行.forName(String,false,ClassLoader)时也不会执行.
2)如果载入Class时没有执行static块则在第一次实例化时执行.比如new ,Class.newInstance()操作
3)static块仅执行一次
loadClass 为classloader主要方法,传入classname,中间做cache查找、双亲委派、安全控制之类的逻辑,最终返回Class
defineClass , 传入byte字节流,根据jvm的bytecode算法,将其解析为Class
========= tomcat classloader ===========
Bootstrap
|
System
|
Common
/ \
Webapp1 Webapp2 ...
bootstrap: jvm/lib/ext/*.jar
system: CLASSPATH/*.jar
common: tomcathome/lib/*.jar
webappx: webapp/root/WEB-INF/lib/*.jar webapp/root/WEB-INF/classes/
上图为tomcat加载器树状结构。于双亲委派策略不同的是,WebappClassLoader会优先加载本地的类,然后再委派双亲。(除了servlet api这样的系统类会滤过)
tomcat下线程默认上下文类加载器是 webapp class loader。
因此,应用app中,类的查找顺序是:
/WEB-INF/classes/
/WEB-INF/lib/*.jar
bootstrap
CLASSPATH
tomcathome/lib/
==================== example code =============
// invisible to parent classloader
public class Test {
public static class A {
public A() {
System.out.println("Cons A");
}
}
public static void main(String[] args) throws Exception {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
ClassLoader pcl = cl.getParent();
pcl.loadClass(Object.class.getName()); // ok to load root class
pcl.loadClass(A.class.getName()); // fail to load child class, throw java.lang.ClassNotFoundException: Test$A
}
}
// thread context classloader
public class Test {
public static class A {
public A() {
System.out.println("Cons A");
}
}
public static void main(String[] args) throws Exception {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
ClassLoader pcl = cl.getParent();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
new A(); // ok, 使用当前类加载器加载A
Class.forName(A.class.getName()); // ok, 使用当前类加载器加载A
ClassLoader.getSystemClassLoader().loadClass(A.class.getName()); // ok,
// 使用系统类加载器
cl.loadClass(A.class.getName()); // throw ex, A class not
// found
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
});
t.setContextClassLoader(pcl);
t.start();
t.join();
}
}
// static block execute time
public class Test {
public static class A {
static {
System.out.println("static");
}
public A() {
System.out.println("Cons A");
}
}
public static void main(String[] args) throws Exception {
Thread.currentThread().getContextClassLoader().loadClass(A.class.getName()); // no static exec
System.out.println("load class");
Class.forName(A.class.getName(), false, ClassLoader.getSystemClassLoader()); // no static exec
System.out.println("class for name0");
Class.forName(A.class.getName()); // static exec
System.out.println("class for name1");
System.out.println("~~~~~~ new A");
new A();
}
}
---------------------- result: -------------------
load class
class for name0
static
class for name1
~~~~~~ new A
Cons A
分享到:
相关推荐
Java ClassLoader定制实例
java classloader classpath 张孝祥
Java ClassLoader Tutorial
理解Java ClassLoader机制
NULL 博文链接:https://sbiigu.iteye.com/blog/260456
java classloader 讲义-淘宝网
Understanding the Java ClassLoader
java classLoader 的全面讲解 从基本概念到具体的应用 里面共有三份资料。
Understanding the Java ClassLoader.pdf
Sun 官方关于 ClassLoader原理的文章,值得一看
破解java加密的ClassLoader.java,在classloader植入破解代码
内容简介: ClassLoader体系结构 类装载器在JVM中并不是唯一的,JVM自带了三个装载器,用户也可以根据自己的需求自定义新的装载器,这些装载器的体系结构可以看作是树状结构,如图1所示:
了解 Java ClassLoader
ClassLoader类加载器讲解,理解JAVA类加载机制
Java ClassLoader 是一个重要的、但又常常被人忽略的 Java 运行时系统组件。它是负责在运行时查找和装入类文件的类。创建自己的 ClassLoader 可以以实用且有趣的方式定制 JVM,这样可以让您彻底重新定义如何将类文件...
深入了解Java_ClassLoader,Bytecde.pdf
主要内容包括 Java类加载机制及加载流程,以及如何定义自己的类加载器,如何实现类的热替换。