浏览 5108 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-03-18
测试环境:JBoss4.0.5.GA 、Gentoo Linux、 spring、ejb(ear工程) 1)使用ant打包脚本的疏忽,把struts action的class同时放在了${ear_file}/${jar_file} 和${ear_file}/${war_file}/WEB-INF/{lib}/${jar_file} 纠正之后,再次修改了struts action的实现类,后者确实不断地更新,但是始终未被执行,而执行的总是前者 2)ant打包,把${xml_config_file}放在了${ear_file}/${jar_file} 和${ear_file}/${war_file}/WEB-INF/classes/${xml_config_file} 之后做了如下的测试: 21)前者不变,更新后者,结果:取新增加的物件出错 22)移除前者,更新后者,结果:可以取到新增加的物件 23)保持前者,新物件的配置作为一个新的文件,同时也放在后者的位置,结果:可以取到新增加的物件。 3)通过IoC注入配置文件的位置,然后读取配置文件的内容(未使用Spring的解析方法,而是自己实现解析): 注入xml位置的配置如下(粗体处): <bean id="test.DataMigrateCenter" class="demo.service.DataMigrateCenter"> <property name="dataExtractDao"><ref bean="demo.dataExtractDao"/></property> <property name="markExtractedDao"><ref bean="demo.markExtractedDao"/></property> <property name="errorsPath" value="/home/demo/Errors/"/> <property name="invoicesPath" value="/home/demo/Invoices/"/> <property name="archivesPath" value="/home/demo/Archives/"/> [b]<property name="sqlPath" value="x.war/WEB-INF/classes/xyz_sql.xml"/>[/b] </bean> xyz_sql.xml的真实位置在/home/jboss/jboss-4.0.5.GA/server/xyz/deploy/x.ear/x.war/WEB-INF/classes/xyz_sql.xml 注入了sqlPath后,交给了一个工具类来解析,这个工具类放在表现层,即打包到war里,代码类似如下 private static Document getRootDocument(String fileName) throws DocumentException{//参数fileName即注入的sqlPath SAXReader reader = new SAXReader(); //Print Code InputStream in = SqlReaderHelper.class.getClassLoader().getResourceAsStream(fileName); Document document = reader.read(in); return document; } 在getRootDocument方法的Print Code处,增加如下打印语句: System.out.println(SqlReaderHelper.class.getClassLoader().getResource("/")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource("")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource("/test.xml")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource("/../test.xml")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource("../test.xml")); System.out.println(Thread.currentThread().getContextClassLoader().getResource("/")); System.out.println(Thread.currentThread().getContextClassLoader().getResource("")); System.out.println(SqlReaderHelper.class.getClass().getClassLoader().getResource("")); 其中,使用的test.xml实际上并不存在; 得到的输出结果(外加了打印语句的本身描述) 17:47:18,213 INFO [STDOUT] -------->>>>>>>>SqlReaderHelper.class.getClassLoader().getResource("/") : null 17:47:18,214 INFO [STDOUT] -------->>>>>>>>SqlReaderHelper.class.getClassLoader().getResource("") : file:/home/jboss/jboss-4.0.5.GA/server/xyz/deploy/x.ear/ 17:47:18,222 INFO [STDOUT] -------->>>>>>>>SqlReaderHelper.class.getClassLoader().getResource("/test.xml") : null 17:47:18,231 INFO [STDOUT] -------->>>>>>>>SqlReaderHelper.class.getClassLoader().getResource("/../test.xml") : null 17:47:18,241 INFO [STDOUT] -------->>>>>>>>SqlReaderHelper.class.getClassLoader().getResource("../test.xml") : null 17:47:18,241 INFO [STDOUT]-------->>>>>>>>Thread.currentThread().getContextClassLoader().getResource("/"):null 17:47:18,242 INFO [STDOUT]-------->>>>>>>>Thread.currentThread().getContextClassLoader().getResource(""):file:/home/jboss/jboss-4.0.5.GA/server/xyz/deploy/x.ear/ 执行到System.out.println(Thread.currentThread().getContextClassLoader().getResource("")); 出错 将test.xml换成一个真实存在的文件 test.jar 并在getRootDocument方法的Print Code处,增加如下打印语句: System.out.println(SqlReaderHelper.class.getClassLoader().getResource("/")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource("")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource("/test.jar")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource("/../test.jar")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource("../test.jar")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource("test.jar")); System.out.println(Thread.currentThread().getContextClassLoader().getResource("/")); System.out.println(Thread.currentThread().getContextClassLoader().getResource("")); System.out.println(SqlReaderHelper.class.getClassLoader().getResource(fileName)); 得到的输出结果(外加了打印语句的本身描述) 17:57:16,882 INFO [STDOUT] -------->>>>>>>SqlReaderHelper.class.getClassLoader().getResource("/") : null 17:57:16,900 INFO [STDOUT] -------->>>>>>>SqlReaderHelper.class.getClassLoader().getResource("") : file:/home/jboss/jboss-4.0.5.GA/server/xyz/deploy/x.ear/ 17:57:16,909 INFO [STDOUT] -------->>>>>>>SqlReaderHelper.class.getClassLoader().getResource("/test.jar") : null 17:57:16,918 INFO [STDOUT] -------->>>>>>>SqlReaderHelper.class.getClassLoader().getResource("/../test.jar") : null 17:57:16,926 INFO [STDOUT] -------->>>>>>>SqlReaderHelper.class.getClassLoader().getResource("../test.jar") : null 17:57:16,926 INFO [STDOUT] -------->>>>>>>SqlReaderHelper.class.getClassLoader().getResource("test.jar") : file:/home/jboss/jboss-4.0.5.GA/server/xyz/deploy/x.ear/test.jar 17:57:16,927 INFO [STDOUT]-------->>>>>>>Thread.currentThread().getContextClassLoader().getResource("/"):null 17:57:16,927 INFO [STDOUT]------->>>>>>>Thread.currentThread().getContextClassLoader().getResource(""):file:/home/jboss/jboss-4.0.5.GA/server/xyz/deploy/x.ear/ 17:57:16,927 INFO [STDOUT] -------->>>>>>>SqlReaderHelper.class.getClassLoader().getResource("fileName") : file:/home/jboss/jboss-4.0.5.GA/server/xyz/deploy/x.ear/cxc3.war/WEB-INF/classes/cxc2sap_sql.xml 通过上述描述,可以简单的得出一些推论: 对1)2) 在应用服务器如JBoss中,加载${ear_file}/${jar_file}的EJB容器 和 加载${ear_file}/${war_file}的Web容器间存在一定的关系,根据ClassLoader的加载机制:当当前类加载器需要加载一个类的时候,首先请求父级的类加载器加载,如果父级加载器无法找到要加载的类(每个加载器仅仅在自己本身的classpath寻找要加载的类),才由当前类加载器来加载,如果加载不到就报错。 根据这个,可认为EJB容器的ClassLoader起了Web容器的父级ClassLoader的作用,即:请求加载一个action class时,当前类加载器是web容器,但是web容器的ClassLoader委托其父级加载器来加载,结果其父亲加载并加载成功了,所以不再加载本来正确的${war_file}/WEB-INF/lib or ${war_file}/WEB-INF/classes下的真正的类了 对3) 这些输出信息则更充分的证明了当使用${Class_name}.class.getClassLoader()的时候,真正起作用的类加载器便是父级类加载器,即使EJB容器的ClassLoader,从而得到的当前classpath是${ear_file}的路径。 回想过去经历: 基于这些实验,记得曾经遇到这样的错误:把struts.jar也放在了${ear_file}之下,运行报错误。 原因依然是类加载器的两个基本原理: 1)加载的委托机制,见上面的分析 2)当一个类被某一个ClassLoader加载后,与其相关的类都由同一个ClassLoader加载 于是得出如下结论:EJB容器加载了struts.jar,当web容器的ClassLoader加载自己的action class的实现类的时候,需要Action基类,但是根据默认的加载原理,关联的类应该由同一个类加载器完成,现在Action基类被父级的加载器加载(相对于当前),Action的实现类在当前的类加载器,故此发生错误。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |