程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 對於不同級別classloader define的類的問題處理

對於不同級別classloader define的類的問題處理

編輯:關於JAVA

問題描述:程序代碼中,執行下列語句:Object mapperObj = Class.forName(mapperClassName).newInstance();MapperInterface mapper = (MapperInterface)mapperObj; 報ClassCastException。

bug fix: 1.分別取得運行環境下mapperObj和MapperInerface.class的 classloader: mapperObj.getClass().getClassLoader() : sun.misc.Launcher$AppClassLoader MapperInterface.class.getClass().getClassLoader() : WebContainerClassLoader2.由jvm classload 機制可知,jvm load class 分四個層次: 第一層為bootstrapclassloader : 主要負責load rt.jar等jvm必須的jar包中的類。 第二層為extclassloader : 主要負責load 被置於java.ext.dirs屬性值所指路徑(默認%Java_HOME%/lib/ext) 中所有的class.其實現類為sun.misc.Launcher$ExtClassLoader 第三層為systemclassloader : 負責load 被置於CLASSPATH路徑中的類。 其實現類一般為sun.misc.Launcher$AppClassLoader 第四層為appclassloader : 由應用程序設計者繼承ClassLoader並實現完成相應user-defined ClassLoader。用於根據應用程序需要加載並不是設計時就知道的類。

詳細的load策略偶就不多寫了,很多文章上都有,總之兩句話: 當define一個類的時候,低層classloader會向上層詢問是否已經define,有則直接拿來用;當load一個類的時候,同樣低層向高層詢問是否能find到,能就直接拿來用。

由此可知,由於原有系統原因, mapperObj被 systemclassloader define;而這裡使用的接口是被appclassloader WebContainerClassLoader define的。所以會造成 ClassCastException錯誤。用instanceof也可發現mapperObj 確實不是 MapperInterface的實例。

由於原系統原因,無法通過改動其他代碼完成更換mapperObj classload的動作,而運行到當前代碼時,mapperObj 已經被define,所以無法通過forName方法的參數更改其class loader,後面的代碼就無法調用其方法。

解決方法:采用類反射,換有Object定義的屬性接 mapperObj;在下面的代碼中,利用mapperObj.getClass().getInterface()方法判斷是否其繼承了 MapperInterface。 然後用反射調用其方法。例:

mapper = Class.forName(mapperClassName).newInstance();

Class[] tmpInterface = mapper.getClass().getInterfaces(); for(int i=0 ;i

if(flag){ Class[] tc = new Class[2] ; tc[0] = String.class; tc[1] = HttpServletRequest.class; Method mapperFunc = mapper.getClass().getMethod( "mapFunction", tc ); Object res = mapperFunc.invoke( mapper, new Object[] { event.getServletClassName(),req } );}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved