博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
分析Java的类加载器与ClassLoader(二):classpath与查找类字节码的顺序,分析ExtClassLoader与AppClassLoader的源码...
阅读量:5942 次
发布时间:2019-06-19

本文共 3283 字,大约阅读时间需要 10 分钟。

先回顾一下classpath

classpath的作用:

        classpath的作用是指定查找类的路径:当使用java命令执行一个类(类中的main方法)时,会从classpath中进行查找这个类。 

指定classpath的方式一: 
        设置环境变量CLASSPATH,多个路径之间使用英文的分号隔开,也可以指定为jar包路径。 
         示例:CLASSPATH=c:/myclasses/;c/mylib/aa.jar;c:/mylib/bb.jar;. 
         注意:在Windows中不区分大小写,所以指定的环境变量名为classpath或是ClassPath都一样。 
指定classpath的方式二: 
         在执行java命令时通过-classpath参数指定。 
         示例:java -classpath c:/myclasses/;c:/mylib/aa.jar cn.itcast.MainApp 
         注意:这样就会只是用这个参数指定的classpath,找不到类就报错,不会使用CLASSPATH环境变量! 
指定classpath时各个路径的顺序: 
        试验的结论是 按classpath中指定的顺序,先从前面的路径中查找,如果找不到,在从下一个路径中查找,直到找到类字节码或是报NoClassDefFoundError。 
另外一种指定类路径方式: 
        把类字节码文件打成jar包,并放到JRE的lib/ext/目录下,这样在执行时就可以直接找到这个类而不需要指定classpath了。 

类加载器与classpath

从上一个文章中我们知道了类加载器默认使用三个: 

1,Bootstrap ClassLoader,启动类加载器,负责加载核心Class(即所有java.*开头的Class)。 
2,Extension ClassLoader,扩展类加载器,负责加载存放在JRE的lib/ext/目录下的jar包中的Class。 
3,Application ClassLoader,应用程序类加载器,负责加载应用程序自身的类(CLASSPATH目录中的Class)。 

分析ExtClassLoader

        Extension ClassLoader负责加载扩展类路径中的类(默认为JRE的lib/ext/目录) ,也就是说只要把jar包放到这个目录中,就可以直接使用里面的类字节码而不需要指定classpath !注意这要求一定要在这个目录中放jar包,直接把.class文件放到这个目录中不行。分析一下源码(sun.misc.Launcher$ExtClassLoader类):

static class ExtClassLoader extends URLClassLoader { private File[] dirs; // 先看这个方法 public static ExtClassLoader getExtClassLoader() throws IOException { // 调用getExtDirs()方法获取配置的扩展类路径 final File[] dirs = getExtDirs(); try { // 使用getExtDirs()方法返回的路径生成一个新的ClassLoader实例 return (ExtClassLoader) AccessController.doPrivileged(new PrivilegedExceptionAction() { public Object run() throws IOException { int len = dirs.length; for (int i = 0; i < len; i++) { MetaIndex.registerDirectory(dirs[i]); } return new ExtClassLoader(dirs); } }); } catch (java.security.PrivilegedActionException e) { throw (IOException) e.getException(); } } // 再看这个方法 private static File[] getExtDirs() { // 获取配置的扩展类路径 String s = System.getProperty("java.ext.dirs"); File[] dirs; if (s != null) { StringTokenizer st = new StringTokenizer(s, File.pathSeparator); int count = st.countTokens(); dirs = new File[count]; for (int i = 0; i < count; i++) { dirs[i] = new File(st.nextToken()); } } else { dirs = new File[0]; } return dirs; } // 其他代码略 ... }

         Application ClassLoader负责加载CLASSPATH目录中的Class ,也就是说classpath是给这个类加载器用的。分析一下源码(sun.misc.Launcher$AppClassLoader类): 

static class AppClassLoader extends URLClassLoader { public static ClassLoader getAppClassLoader(final ClassLoader extcl) throws IOException { // 获取配置的classpath路径 // 注1:可以通过设置classpath环境变量改变java.class.path的值。 // 注2:也可以在程序中使用System.setProperty("java.class.path", "newpath")改变java.class.path的值。 final String s = System.getProperty("java.class.path"); final File[] path = (s == null) ? new File[0] : getClassPath(s); // 使用classpath中的路径生成一个新的ClassLoader实例并返回 return (AppClassLoader) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { URL[] urls = (s == null) ? new URL[0] : pathToURLs(path); return new AppClassLoader(urls, extcl); } }); } // 其他代码略 ... }

 

当AppClassLoader遇上ExtClassLoader

        如果JRE的lib/ext/目录下的jar包有某个类,我们指定的classpath中也有这个类,会怎么样呢?想想类加载查找类字节码的策略!结论是会执行lib/ext/xx.jar中的类! 因为类加载器使用委托模式进行类加载,并且ExtClassLoader是AppClassLoader的上级,所以AppClassLoader会先让ExtClassLoader加载。如果父的类加载器没有找到,自己才会加载。 

结论: 
1,把jar包放到扩展类路径中就可以直接使用其中的类(默认是JRE的lib/ext/目录)
2,classpath是给AppClassLoader配置的。 
3,如果扩展类路径中有某个类,classpath中也有这个类,则会使用扩展类路径中的类。 

 

http://www.tuicool.com/articles/bQFnqmi

转载地址:http://ormtx.baihongyu.com/

你可能感兴趣的文章
Oracle——20数据库恢复与备份
查看>>
鼠标坏了你别扔,可以修的
查看>>
CentOS 中使用yum时常见的一种提示信息
查看>>
记一次ssh登录异常
查看>>
01-利用思维导图梳理JavaSE-Java语言基础
查看>>
RocketMQ几种搭建模式说明
查看>>
程序分析思路
查看>>
beangle commons 4.0.0 release
查看>>
数据仓库中的维度表和事实表概述
查看>>
淘气的页数 - 格式化字符串
查看>>
使用vim保存权限不够的文件
查看>>
nodejs如何利用rpc调用python
查看>>
kinect c++
查看>>
大数据,只是为了赚钱么?
查看>>
jvm系列(四):jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)
查看>>
IntelliJ IDEA上操作GitHub
查看>>
js时间日期友好显示
查看>>
java使用Calendar类获取常用简单工具类
查看>>
自定义listview
查看>>
C++中文转码问题(GB2312 -> UTF8)
查看>>