zz~ ClassLoader的加载过程及分析一
2011-03-18 15:17
579 查看
发表时间:2010-07-01
最后修改:2010-07-01
<
>
猎头职位: 北京:
JavaEye招聘Java搜索工程师
相关文章:
classloader相关基础知识
<<Java深度历险>>学习
jvm classloader
推荐圈子: Scala圈子
更多相关推荐
一,ClassLoader的大体过程
如图:
详解:
虚拟机一启动,会先做一些初始化的动作。一旦初始化动作完成之
后,就会产生第一个类别加载器,即所谓的Bootstrap Loader,Bootstrap Loader 是由C++
所撰写而成,这个Bootstrap Loader所做的初始工作中,除了也做一些基本的初始化动作之外,最重要的就是加载定义在sun.misc
命名空间底下的Launcher.java 之中的ExtClassLoader( 因为是inner class
,所以编译之后会变成Launcher$ExtClassLoader.class) ,并设定其Parent
为null,代表其父加载器为Bootstrap Loader 。然后Bootstrap Loader ,再要求加载定义于sun.misc
命名空间底下的Launcher.java 之中的AppClassLoader( 因为是inner
class,所以编译之后会变成Launcher$AppClassLoader.class) ,并设定其Parent
为之前产生的ExtClassLoader 实例。
由以上可以看出,classLoader是由下向上查找,上层的不能向下查找。
二,ClassLoader中类的关系
如图:
详解:
AppClassLoader 和ExtClassLoader
都是URLClassLoader 的子类别。由于它们都是URLClassLoader 的子类别,所以它们也应该有URL
作为搜寻类别档的参考,由原始码中我们可以得知,AppClassLoader 所参考的URL 是从系统参java.class.path
取出的字符串所决定,而java.class.path 则是由我们在执行java.exe 时,利用 –cp 或-classpath
或CLASSPATH 环境变量所决定。
ClassLoader的loadClass代码:
Java代码
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
) {
//到parentclassloader中去查找(像这个parent还有parent递归方式进行查找)
c = parent.loadClass(name, false
);
} else
{
//启动类加载器进行加载
c = findBootstrapClass0(name);
}
} catch
(ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
//当一直都没有找到时,启动当前类的findClass进行查找
//这个通常也是我们扩展的地方
c = findClass(name);
}
}
if
(resolve) {
resolveClass(c);
}
return
c;
}
详解:
java文件的编译和Class的载入执行,都是使用Launcher初始化的appclassloader作为类
载
入器的,我们无法动态的改变App classloader,更无法让JVM使用我们自己的classloader来替换system
classloader,根据全盘负责原则,就限制了编译和运行时,我们无法直接显式的使用一个system
classloader寻找不到的Class,即我们只能使用Java核心类库,扩展类库和CLASSPATH中的类库中的Class。
而且我们也无法载入以java.lang....开头的包,进行了限制
三,分析及证明:
可以用最底层的ClassLoader得到某一个类(Test)时,Test.class.getClassLoader()就可知当前类在哪一个层次的ClassLoader下被加载
1,BootStrapClassLoader
Java代码
Class clazz=Class.forName(
"java.lang.Object"
);
System.out.println(clazz.getClassLoader());
//输出为null,因为bootstrap在java中不是类,而是由c++编写的
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
for
(
int
i =
0
; i < urls.length; i++) {
System.out.println(urls[i].getFile());
}//用这个进行查找bootstrap所加载的是哪些jar包
2,ExtClassLoader
Java代码
clazz = Class.forName(
"sun.net.spi.nameservice.dns.DNSNameService"
);
clazzLoader = clazz.getClassLoader();
System.out.println(" sun.net.spi.nameservice.dns.DNSNameService's loader is "
+ clazzLoader);
//在些可以说明ExtClassLoader所加载的类
3,AppClassLoader
当前工程中class与lib都是用此Loader加载
可以通过ClassLoader.getSystemClassLoader()可以获取到AppClassLoader的
4,DefineClassLoader
可以继承URLClassLoader或ClassLoader
当继承ClassLoader重写findClass()方法,parent会相应是AppClassLoader-->ExtClassLoader-->BootStrapClassLoader
URLClassLoader可以直接设置url即可
问题:
由于自己自定义了一个DefineClassLoader替代了加载ant的ClassLoader,另外添加自己jar包,
但是在执行ant编译时,要执行tools.jar里的javac类,在执行javac这个类时,是处在AppClassLoader
下,找不到我添加的DefineClassLoader的jar包
------------------------------------------------
其他一些相应的操作(参考)
在预设情况下,AppClassLoader的搜寻路径为”.”(
目前所在目录),如果使用-classpath 选项(与-cp 等效),就可以改变AppClassLoader
的搜寻路径,如果没有指定-classpath 选项,就会搜寻环境变量CLASSPATH 。如果同时有CLASSPATH
的环境设定与-classpath 选项,则以-classpath 选项的内容为主,CLASSPATH 的环境设定与-classpath
选项两者的内容不会有加成的效果。至于ExtClassLoader
也有相同的情形,不过其搜寻路径是参考系统参数java.ext.dirsBootstrap Loader
,我们可以经由查询由系统参数sun.boot.class.path 得知Bootstrap Loader 用来搜寻类别的路径java
-Dsun.boot.class.path=请回头看到java.class.path
与sun.boot.class.path,也就是说,AppClassLoader 与Bootstrap Loader
会搜寻它们所指定的位置(或JAR 文件),如果找不到就找不到了,AppClassLoader 与Bootstrap Loader
不会递归式地搜寻这些位置下的其他路径或其他没有被指定的JAR
文件。反观ExtClassLoader,所参考的系统参数是java.ext.dirs,意思是说,他会搜寻底下的所有JAR 文件以及classes
目录,作为其搜寻路径(所以您会发现上面我们在测试的时候,如果加入-Dsun.boot.class.path=c:windows
选项时,程序的起始速度会慢了些,这是因为c:windows 目录下的文件很多,必须花额外的时间来列举JAR 文件)。
在命令行下参数时,使用–classpath / -cp /
环境变量CLASSPATH 来更改AppClassLoader 的搜寻路径,或者用 –Djava.ext.dirs
来改变ExtClassLoader的搜寻目录,两者都是有意义的。可是用–Dsun.boot.class.path 来改变Bootstrap
Loader 的搜寻路径是无效。这是因为AppClassLoader与ExtClassLoader
都是各自参考这两个系统参数的内容而建立,当您在命令行下变更这两个系统参数之后,AppClassLoader
与ExtClassLoader在建立实例的时候会参考这两个系统参数,因而改变了它们搜寻类别文件的路径;
而系统参数sun.boot.class.path 则是默认与Bootstrap Loader
的搜寻路径相同,就算您更改该系统参与,与BootstrapLoader 完全无关,AppClassLoader 与ExtClassLoader
在整个虚拟机之中只会存有一份,一旦建立了,其内部所参考的搜寻路径将不再改变,也就是说,即使我们在程序里利用
System.setProperty() 来改变系统参数的内容,仍然无法更动AppClassLoader 与ExtClassLoader
的搜寻路径。因此,执行时期动态更改搜寻路径的设定是不可能的事情。
参考网址:http://blog.sina.com.cn/s/blog_4efddaed01008ypj.html
http://syue.com/Software/JAVA/15709.html
最后修改:2010-07-01
<
>
猎头职位: 北京:
JavaEye招聘Java搜索工程师
相关文章:
classloader相关基础知识
<<Java深度历险>>学习
jvm classloader
推荐圈子: Scala圈子
更多相关推荐
一,ClassLoader的大体过程
如图:
详解:
虚拟机一启动,会先做一些初始化的动作。一旦初始化动作完成之
后,就会产生第一个类别加载器,即所谓的Bootstrap Loader,Bootstrap Loader 是由C++
所撰写而成,这个Bootstrap Loader所做的初始工作中,除了也做一些基本的初始化动作之外,最重要的就是加载定义在sun.misc
命名空间底下的Launcher.java 之中的ExtClassLoader( 因为是inner class
,所以编译之后会变成Launcher$ExtClassLoader.class) ,并设定其Parent
为null,代表其父加载器为Bootstrap Loader 。然后Bootstrap Loader ,再要求加载定义于sun.misc
命名空间底下的Launcher.java 之中的AppClassLoader( 因为是inner
class,所以编译之后会变成Launcher$AppClassLoader.class) ,并设定其Parent
为之前产生的ExtClassLoader 实例。
由以上可以看出,classLoader是由下向上查找,上层的不能向下查找。
二,ClassLoader中类的关系
如图:
详解:
AppClassLoader 和ExtClassLoader
都是URLClassLoader 的子类别。由于它们都是URLClassLoader 的子类别,所以它们也应该有URL
作为搜寻类别档的参考,由原始码中我们可以得知,AppClassLoader 所参考的URL 是从系统参java.class.path
取出的字符串所决定,而java.class.path 则是由我们在执行java.exe 时,利用 –cp 或-classpath
或CLASSPATH 环境变量所决定。
ClassLoader的loadClass代码:
Java代码
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
) {
//到parentclassloader中去查找(像这个parent还有parent递归方式进行查找)
c = parent.loadClass(name, false
);
} else
{
//启动类加载器进行加载
c = findBootstrapClass0(name);
}
} catch
(ClassNotFoundException e) {
// If still not found, then invoke findClass in order
// to find the class.
//当一直都没有找到时,启动当前类的findClass进行查找
//这个通常也是我们扩展的地方
c = findClass(name);
}
}
if
(resolve) {
resolveClass(c);
}
return
c;
}
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) { //到parentclassloader中去查找(像这个parent还有parent递归方式进行查找) c = parent.loadClass(name, false); } else { //启动类加载器进行加载 c = findBootstrapClass0(name); } } catch (ClassNotFoundException e) { // If still not found, then invoke findClass in order // to find the class. //当一直都没有找到时,启动当前类的findClass进行查找 //这个通常也是我们扩展的地方 c = findClass(name); } } if (resolve) { resolveClass(c); } return c; }
详解:
java文件的编译和Class的载入执行,都是使用Launcher初始化的appclassloader作为类
载
入器的,我们无法动态的改变App classloader,更无法让JVM使用我们自己的classloader来替换system
classloader,根据全盘负责原则,就限制了编译和运行时,我们无法直接显式的使用一个system
classloader寻找不到的Class,即我们只能使用Java核心类库,扩展类库和CLASSPATH中的类库中的Class。
而且我们也无法载入以java.lang....开头的包,进行了限制
三,分析及证明:
可以用最底层的ClassLoader得到某一个类(Test)时,Test.class.getClassLoader()就可知当前类在哪一个层次的ClassLoader下被加载
1,BootStrapClassLoader
Java代码
Class clazz=Class.forName(
"java.lang.Object"
);
System.out.println(clazz.getClassLoader());
//输出为null,因为bootstrap在java中不是类,而是由c++编写的
URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs();
for
(
int
i =
0
; i < urls.length; i++) {
System.out.println(urls[i].getFile());
}//用这个进行查找bootstrap所加载的是哪些jar包
Class clazz=Class.forName("java.lang.Object"); System.out.println(clazz.getClassLoader()); //输出为null,因为bootstrap在java中不是类,而是由c++编写的 URL[] urls=sun.misc.Launcher.getBootstrapClassPath().getURLs(); for (int i = 0; i < urls.length; i++) { System.out.println(urls[i].getFile()); }//用这个进行查找bootstrap所加载的是哪些jar包
2,ExtClassLoader
Java代码
clazz = Class.forName(
"sun.net.spi.nameservice.dns.DNSNameService"
);
clazzLoader = clazz.getClassLoader();
System.out.println(" sun.net.spi.nameservice.dns.DNSNameService's loader is "
+ clazzLoader);
//在些可以说明ExtClassLoader所加载的类
clazz = Class.forName("sun.net.spi.nameservice.dns.DNSNameService"); clazzLoader = clazz.getClassLoader(); System.out.println(" sun.net.spi.nameservice.dns.DNSNameService's loader is " + clazzLoader); //在些可以说明ExtClassLoader所加载的类
3,AppClassLoader
当前工程中class与lib都是用此Loader加载
可以通过ClassLoader.getSystemClassLoader()可以获取到AppClassLoader的
4,DefineClassLoader
可以继承URLClassLoader或ClassLoader
当继承ClassLoader重写findClass()方法,parent会相应是AppClassLoader-->ExtClassLoader-->BootStrapClassLoader
URLClassLoader可以直接设置url即可
问题:
由于自己自定义了一个DefineClassLoader替代了加载ant的ClassLoader,另外添加自己jar包,
但是在执行ant编译时,要执行tools.jar里的javac类,在执行javac这个类时,是处在AppClassLoader
下,找不到我添加的DefineClassLoader的jar包
------------------------------------------------
其他一些相应的操作(参考)
在预设情况下,AppClassLoader的搜寻路径为”.”(
目前所在目录),如果使用-classpath 选项(与-cp 等效),就可以改变AppClassLoader
的搜寻路径,如果没有指定-classpath 选项,就会搜寻环境变量CLASSPATH 。如果同时有CLASSPATH
的环境设定与-classpath 选项,则以-classpath 选项的内容为主,CLASSPATH 的环境设定与-classpath
选项两者的内容不会有加成的效果。至于ExtClassLoader
也有相同的情形,不过其搜寻路径是参考系统参数java.ext.dirsBootstrap Loader
,我们可以经由查询由系统参数sun.boot.class.path 得知Bootstrap Loader 用来搜寻类别的路径java
-Dsun.boot.class.path=请回头看到java.class.path
与sun.boot.class.path,也就是说,AppClassLoader 与Bootstrap Loader
会搜寻它们所指定的位置(或JAR 文件),如果找不到就找不到了,AppClassLoader 与Bootstrap Loader
不会递归式地搜寻这些位置下的其他路径或其他没有被指定的JAR
文件。反观ExtClassLoader,所参考的系统参数是java.ext.dirs,意思是说,他会搜寻底下的所有JAR 文件以及classes
目录,作为其搜寻路径(所以您会发现上面我们在测试的时候,如果加入-Dsun.boot.class.path=c:windows
选项时,程序的起始速度会慢了些,这是因为c:windows 目录下的文件很多,必须花额外的时间来列举JAR 文件)。
在命令行下参数时,使用–classpath / -cp /
环境变量CLASSPATH 来更改AppClassLoader 的搜寻路径,或者用 –Djava.ext.dirs
来改变ExtClassLoader的搜寻目录,两者都是有意义的。可是用–Dsun.boot.class.path 来改变Bootstrap
Loader 的搜寻路径是无效。这是因为AppClassLoader与ExtClassLoader
都是各自参考这两个系统参数的内容而建立,当您在命令行下变更这两个系统参数之后,AppClassLoader
与ExtClassLoader在建立实例的时候会参考这两个系统参数,因而改变了它们搜寻类别文件的路径;
而系统参数sun.boot.class.path 则是默认与Bootstrap Loader
的搜寻路径相同,就算您更改该系统参与,与BootstrapLoader 完全无关,AppClassLoader 与ExtClassLoader
在整个虚拟机之中只会存有一份,一旦建立了,其内部所参考的搜寻路径将不再改变,也就是说,即使我们在程序里利用
System.setProperty() 来改变系统参数的内容,仍然无法更动AppClassLoader 与ExtClassLoader
的搜寻路径。因此,执行时期动态更改搜寻路径的设定是不可能的事情。
参考网址:http://blog.sina.com.cn/s/blog_4efddaed01008ypj.html
http://syue.com/Software/JAVA/15709.html
相关文章推荐
- ClassLoader的加载过程及分析一
- 7.OP-TEE+qemu的启动过程分析--加载optee_os和rootfs
- 浏览器加载、渲染和解析过程的黑箱分析[ZT]
- 关于Classloader的总结!loadClass的分析和加载细节的分析
- 类的加载、连接与初始化过程的详细分析(上)
- 模块加载过程代码分析1
- Android WebView加载Chromium动态库的过程分析
- android输入设备配置文件加载过程分析
- Fragment加载过程分析。
- SpringMVC 项目配置文件加载过程分析(spring4.1.4)
- django源码分析--03app加载过程
- Webkit页面加载过程分析(1)-发送请求篇
- 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)
- Chromium扩展(Extension)的Content Script加载过程分析
- 类加载过程实例分析
- 模块加载过程分析:INSMOD DEMODEV.KO
- 浏览器加载、渲染和解析过程的黑箱分析
- java中类加载的全过程及内存图分析
- Java学习之类加载全过程_JVM内存分析_反射机制核心原理_常量池理解
- Tomcat7源码分析——启动过程和类加载器