您现在的位置: 主页 > 上位机技术 > JAVA > 向高手请教ant构建工具的类装载器问题
本文所属标签:
为本文创立个标签吧:

向高手请教ant构建工具的类装载器问题

来源:网络整理 网络用户发布,如有版权联系网管删除 2018-07-23 

问题概述:每个ClassLoader本身只能分别加载特定位置和目录中的类,但是,ClassLoader被设计成了一种委托模式,使得某一个ClassLoader可以委托它的父级类装载器去加载类,从而让应用程序可以借助某一个子级的ClassLoader去多个位置和目录中进行类的加载。这就好比“儿子”除了可以花自己的钱,他还可以花“父亲”的钱,“父亲”又可以花“父亲的父亲”的钱,所以,最终能通过“儿子”花出去的钱包括他历代前辈的钱。类装载器一级级委托到BootStrap类加载器,当BootStrap无法加载当前所要加载的类时,然后才一级级回退到子孙类装载器去进行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异常。

现在的问题是,我编写了一个类装载器去加载特定目录中的类,使用java.exe测试这个类加载器时,测试结果完全正常,可以看到委托效果。而我使用ant工具去调用测试程序时,结果就有点问题了,我编写的类装载器似乎并没有委托其父级类加载器去加载类,而总是自己加载。由于本人才学疏浅,且实在没有精力去研究ant工具的源码,无法了解其类加载内部细节,现在特针对这个问题,向真正的java高手们请教。为了便于高手们快速了解我的问题所在,也便于一些中手们学习,我写出了详细的实验步骤,对于java新手,建议不要参与讨论了,免得我耽误了您宝贵时间。

1.源程序:MainClass.java

源程序:AuxiliaryClass.java

2.源文件及build结果文件的目录结构

3.build.xml文件内容

4.进入project目录中运行ant,执行结果正常,如下:

5.修改build.xml文件,将最后名称为“run”的target(执行目标)修改成如下形式,即不设置其中的<classpath>子元素。

再次执行ant,将报告如下错误信息:

在执行ant的命令行窗口中设置classpath环境变量:

再次执行ant,执行结果正常,如下:

这个实验说明CLASSPATH环境变量对ant起了作用,并且在这种情况下,类的加载入器不再是 org.apache.tools.ant.loader.AntClassLoader2,而是java.net.URLClassLoader。

6.修改build.xml文件,让ant生成的AuxiliaryClass.class文件与MainClass文件位于不同的目录中,即结果目录如下:

修改后的build.xml文件内容如下:

因为第一个javac任务编译MainClass.java时,也会编译它引用的AuxiliaryClass.java文件,所以,增加了delete任务删除掉生成的AuxiliaryClass.class文件,然后再使用一个javac任务将AuxiliaryClass.java编译到另外一个目录中。java任务中也增加了一个<arg>子元素,用于为java虚拟机传递参数,在这一步暂时不需要这个元素,在下一步的实验中将使用这个元素。

再次执行ant,将报告如下错误信息:

在执行ant的命令行窗口中设置classpath环境变量,将编译后生成的AuxiliaryClass.class类所在的目录也加入进CLASSPATH环境变量中:

再次执行ant,执行结果正常,如下:

这个实验再次说明CLASSPATH环境变量对ant起了作用,将AuxiliaryClass.class放在了classpath环境变量指定的另外一个目录中,也可以被ant工具的java任务装载。

7.修改MainClass.java文件,让其扩展成一个类装载器,专门负责从一个特定的目录中去加载类。MainClass同时也作为一个启动运行类,在其main方法中通过MainClass这个类装载器加载AuxiliaryClass类。

源程序:MainClass.java

按如下方式执行ant命令,其中第一个参数为要加载的类,第二个参数为到哪个目录中去加载如类。

命令执行的结果为:

从第一行打印的内容上可以看到:AuxiliaryClass类的类装载器为MainClass。这个结果与我的预期不同,因为按照类加载器的委托机制,MailClass类加载器将先委托其父级类装载器AppClassLoader加载AuxiliaryClass,而AuxiliaryClass所在的目录f:project已经在第6步中加入到了Classpath环境变量当中,AppClassLoader可以成功加载AuxiliaryClass,所以,第一行打印出来的类装载器应该是AppClassLoader。为了印证我的想法,我改用java.exe来执行上面的程序:

执行结果如下:

可见,使用java.exe执行上面的程序时,AuxiliaryClass类的类装载器确实是MailClass类加载器的父级类加载器AppClassLoader。这就是我这次问题的内容:为什么在ant环境下运行,MailClass类加载器没有委托其父级类装载器AppClassLoader加载AuxiliaryClass类,而是自己加载了呢?就这个问题,本人向真正的Java高手们请教?请您帮忙解释一下原因。

8.为了印证类加载器的委托机制,我们重新设置CLASSPATH环境变量,该环境变量不再包含AuxiliaryClass所在的目录f:project。

set CLASSPATH=f:projectclasses;

用cd命令进入f:目录(避免当前目录的干扰),接着重复执行如下的java命令:

java cn.itcast.MainClass cn.itcast.AuxiliaryClass projectcnitcast

执行结果如下:

可见,这次AuxiliaryClass类的类装载器是MailClass类,这是因为MailClass类装载器的父级类加载器AppClassLoader找不到AuxiliaryClass类,加载过程又退回到MailClass类装载器,MailClass类装载器从projectcnitcast目录中成功找到AuxiliaryClass类,所以,这次打印出的类装载器为MailClass。



              查看评论 回复



嵌入式交流网主页 > 上位机技术 > JAVA > 向高手请教ant构建工具的类装载器问题
 目录 装载 加载

"向高手请教ant构建工具的类装载器问题"的相关文章

网站地图

围观()