<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    cuiyi's blog(崔毅 crazycy)

    記錄點滴 鑒往事之得失 以資于發展
    數據加載中……

    ClassLoader專題(四):部署ear包出錯引發的ClassLoader的思考

    ClassLoader專題(一):ClassLoader基礎
    ClassLoader專題(二):從Servlet容器看ClassLoader機制的妙用
    ClassLoader專題(三):引文
    ClassLoader專題(四):部署ear包出錯引發的ClassLoader的思考

    應用服務器常常包含多個容器,當前使用的是JBoss,在部署ear包的時候,遇到了一些比較有意思的問題,遂隨著不斷的推敲,從而解決了問題,也對classloader在應用服務器如JBoss中有了一點的推測(不當之處請光顧的朋友指出)。
    測試環境: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/cuiyi/demo/Errors/"/>
            
    <property name="invoicesPath" value="/home/cuiyi/demo/Invoices/"/>
            
    <property name="archivesPath" value="/home/cuiyi/demo/Archives/"/>
            
            
    <property name="sqlPath"      value="x.war/WEB-INF/classes/xyz_sql.xml"/>
        
    </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的實現類在當前的類加載器,故此發生錯誤。



    posted on 2008-03-18 18:08 crazycy 閱讀(2751) 評論(0)  編輯  收藏 所屬分類: JavaSE語言

    主站蜘蛛池模板: 国产乱子伦精品免费无码专区| 亚洲视频免费观看| 免费一看一级毛片全播放| 亚洲爆乳成av人在线视菜奈实| 一二三四视频在线观看中文版免费| 亚洲国产综合精品| 综合在线免费视频| 亚洲日韩国产精品乱-久| 国产成人免费高清激情视频| 在线亚洲午夜片AV大片| 最近免费中文字幕大全视频| 亚洲爆乳无码精品AAA片蜜桃| 国产一级淫片a免费播放口之| 特级aaaaaaaaa毛片免费视频| 国产偷国产偷亚洲高清日韩| 中文字幕永久免费视频| 亚洲av永久无码精品国产精品| 91青青国产在线观看免费| 亚洲永久中文字幕在线| 女人被免费视频网站| 一区免费在线观看| 午夜亚洲国产理论秋霞| 免费a级毛片高清视频不卡| 理论秋霞在线看免费| 久热综合在线亚洲精品| 国产精品久久久久免费a∨| 黄色大片免费网站| 亚洲国产精品自在在线观看 | 黄色永久免费网站| 亚洲欧美日韩国产成人| 亚洲午夜无码AV毛片久久| 一级毛片免费观看不卡的| 亚洲综合无码一区二区痴汉| 中文字幕亚洲无线码a| 四虎成年永久免费网站| 免费看一级高潮毛片| 麻豆亚洲av熟女国产一区二| 国产在线不卡免费播放| 国产成人精品免费久久久久| 在线aⅴ亚洲中文字幕| 亚洲午夜未满十八勿入网站2|