标签:虚拟机 classloader 线程 jvm
在写这篇文章之前特意读了下十多年前的一本书的某些章节 《深入java虚拟机》,收获还是挺大,至少知道了类加载器在安全方面起到了至关重要的作用,废话不多说,来看看类加载器是什么。
我们知道我们写的java程序最终都要编译成class文件,这是一种二进制的文件,被设计的非常紧凑,因为这有利于class文件在网络中的传输,奠定java语言在分布式领域的优势,另一个优势是跨平台,也就是所谓的一次编译到处运行。当jvm执行class文件的时候,首先要做的肯定是去加载它,类加载器主要做的事情就是去加载class文件。JVM中的类加载机制是双亲委派,不知道为啥叫双亲,好奇怪的名字,姑且也这样叫吧,那么什么叫双亲委派呢?再解释这个概念的时候,先来看下JVM中默认提供的三种类加载器。
启动类加载器,bootstrap这个加载器由C++提供,java程序无法获取,此加载器也是加载器的祖宗,它没有父亲。确切的讲它加载的是jre/lib下面的jdk核心类库,也可以由-Xbootclasspath启动参数指定,值得一提的是该加载器只加载特定名字的jar,比如rt.jar,非法的jar它不去加载。
扩展类加载器(Extension ClassLoader),扩展类加载器由java语言本身实现,负责加载JAVA_HOME/lib/ext目录中的,或者被java.ext.dirs系统变量所指定的路径中的所有类库,我们是可以直接使用该加载器的,它是bootstrap加载器的孩子。
应用程序类加载器(Application
ClassLoader),也叫系统类加载器,一开始学习java的时候总会提到classpath的概念,没错,这个加载器就是加载我们指定的classpath下的类。它是扩展类加载器的孩子。同样是由java程序编写,我们也可以扩展它。
介绍完默认的三种类加载器,双亲委派的模型就很容易理解了,在jdk的最初版本的时候,类加载还不是这个模型,在jdk1.2的时候才正式有了这个概念。也就是当我们的系统类加载器试图通过loadClass去加载一个类的时候,会先把加载的动作传递给父加载器(如果有),就这样一层层的传递,如果最终的根加载器没有加载到该类,则依次返回,由子类加载,如果所有的类加载器都加载不到,则报ClassNotFoundException错误。之所以采用这样一个模型是因为考虑到安全性,假设我们自己定义了一个java.lang.Integer类的实现,并指定类加载器去加载,试想如果jvm加载的Integer类不是jdk提供的,而是我们自己写的,这将是非常危险的。但是采用委派的方式,我们自己定义的Integer类将永远不会得到加载的机会。
看下双亲委派源码:
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // First, check if the class has already been loaded //首先检查这个类有没有被加载,这里的name是类的权限定名 Class c = findLoadedClass(name); if (c == null) { //如果还没被加载,并且有父加载器,则委派给父加载器加载 try { if (parent != null) { c = parent.loadClass(name, false); } else { //如果没有父亲,则使用bootstrap加载,可以想象,该方法最终是个native方法 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; }
标签:虚拟机 classloader 线程 jvm
原文地址:http://blog.csdn.net/tangyongzhe/article/details/42247289