標籤:oracle 依賴庫 ssl run art ref mave param html
JAVA的父類委託載入機制,再帶來巨大便利性和效率提升的同時的同時也帶來不少麻煩,最直接的就是類衝突造成的問題,以下情境不知道諸位是不是有點熟悉。本文定義的類衝突定義為相同命名空間下的class分散在不通的jar包之中。 1、造成的注入系統混亂。2、造成類型判斷系統混亂,例如 if ((paramObject instanceof CLASSS))判斷失靈3、不同版本class實現方法有升級 例如Ajar包支援getXX(A,B),而另外jar中卻只有getXX(A)4、在資料在運算中的神秘失蹤,如方法A jar中有方法void A(B b),C包中調用A的方法傳入的對象 b和Ajar中的B載入的是有類衝突的B。運算結果可以想而知。 這種現象造成的一個問題就是程式員回說My Code沒有問題,我本地也是正常的....,之類的神奇現象,下面嘗試去解決一下這幾個問題。 1、個人認為首先要對類載入機制有個適當的瞭解。以當前比較流行的tomcat為例:載入順序個人認為講的比較詳細的查閱。http://www.cnblogs.com/xing901022/p/4574961.htmlhttp://www.ibm.com/developerworks/cn/java/j-lo-classloader/ 2、定位一下我的classpath或者項目中會從那幾個路徑中載入,然後找出我的程式到底載入的是哪個呢?可以用該方法在檔案中找出有哪些類有可能造成衝突。
import java.io.IOException;import java.net.URL;import java.net.URLDecoder;import java.util.Enumeration;import java.util.jar.JarEntry;import java.util.jar.JarFile;import java.io.*; public class JarFinder { public static void FindClassInJar(String jarName) throws IOException { String filePath = jarName;if (filePath.endsWith(".jar")) {} elsereturn;java.util.jar.JarFile file = new JarFile(filePath);Enumeration<JarEntry> entrys = file.entries();while (entrys.hasMoreElements()) {JarEntry jar = entrys.nextElement();String tmpJarName = jar.getName(); tmpJarName = tmpJarName.replace(‘/‘, ‘.‘);if (tmpJarName.contains("javax.mail.Multipart")) {System.out.println(tmpJarName + " " + file.getName());}}file.close();} final static void ShowAllFileInDir(File dir) throws Exception {File[] fs = dir.listFiles();for (int i = 0; i < fs.length; i++) {String file = fs[i].getAbsolutePath();FindClassInJar(file);if (fs[i].isDirectory()) {try {ShowAllFileInDir(fs[i]);} catch (Exception e) {}}}} public static void main(String[] args) throws Exception {File root = new File("C:/Program Files/Java/jdk1.8.0_102/jre/lib/ext"); ShowAllFileInDir(root);}}
3、減少相關jar包的數量1、類統一,比如部署在tomcat上的不同項目每個項目多有jar A,那麼不妨把jar A放在tomcat的/common/lib目錄下。2、盡量把能去掉的jar從項目中移除出去 此方法通常可以解決一大部分問題,個人認為也是解決這類問題的一個關鍵思路。 4、代碼版本統一 解決問題的最好辦法就是預防。部署在同一個tomcat下的項目使用的基礎jar包要盡量統一,從制度和規範上解決這個問題。最好能一個公司統一的依賴庫,maven是個不錯的管理方式,公司按照統一的步調處理依賴項。 5、對於不能移除的可以通過控制jar包載入的順序 6、確認不需要的jar包是否已經真從相關路徑中移除。 個人就曾遇到從項目的依賴項中把jar去掉了,但是lib路徑下仍存在這個jar導致的仍然被打到包裡去了,活活鬱悶兩天。 其他有可能用到定位class路徑的方法:
public static String getProjectPath() { java.net.URL url = oracle.sql.NCLOB.class.getProtectionDomain().getCodeSource().getLocation();String filePath = null;try {filePath = java.net.URLDecoder.decode(url.getPath(), "utf-8");} catch (Exception e) {e.printStackTrace();}if (filePath.endsWith(".jar"))filePath = filePath.substring(0, filePath.lastIndexOf("/") + 1);java.io.File file = new java.io.File(filePath);filePath = file.getPath();return filePath;} public static String getRealPath() {String realPath = oracle.sql.NCLOB.class.getClassLoader().getResource("").getFile();//java.io.File file = new java.io.File(realPath);//realPath = file.(); System.out.println(realPath);try {realPath = java.net.URLDecoder.decode(realPath, "utf-8");} catch (Exception e) {e.printStackTrace();} return realPath;} public static String getAppPath(Class<?> cls) {// 檢查使用者傳入的參數是否為空白if (cls == null)throw new java.lang.IllegalArgumentException("參數不可為空!"); ClassLoader loader = cls.getClassLoader();// 獲得類的全名,包括包名String clsName = cls.getName();// 此處簡單判定是否是Java基礎類庫,防止使用者傳入JDK內建的類庫if (clsName.startsWith("java.") || clsName.startsWith("javax.")) {throw new java.lang.IllegalArgumentException("不要傳送系統類別!");}// 將類的class檔案全名改為路徑形式String clsPath = clsName.replace(".", "/") + ".class"; System.out.println(clsPath); // 調用ClassLoader的getResource方法,傳入包含路徑資訊的類檔案名稱java.net.URL url = loader.getResource(clsPath);// 從URL對象中擷取路徑資訊String realPath = url.getPath();System.out.println(realPath);// 去掉路徑資訊中的協議名"file:"int pos = realPath.indexOf("file:");if (pos > -1) {realPath = realPath.substring(pos + 5);}//System.out.println(realPath);// 去掉路徑資訊最後包含類檔案資訊的部分,得到類所在的路徑//pos = realPath.indexOf(clsPath);//realPath = realPath.substring(0, pos - 1);// 如果類檔案被打包到JAR等檔案中時,去掉對應的JAR等打包檔案名稱//if (realPath.endsWith("!")) {// realPath = realPath.substring(0, realPath.lastIndexOf("/"));//}//java.io.File file = new java.io.File(realPath);//realPath = file.getAbsolutePath(); try {realPath = java.net.URLDecoder.decode(realPath, "utf-8");} catch (Exception e) {throw new RuntimeException(e);}return realPath;}
從問題的兩面性來看。這種載入機制也能給我帶來便利性的一面。比如我們要修改jar A中類B的實現,而我們又沒有原始碼,此時這種載入機制就很有用了。 我們只需要在項目的src中按照B的包名搭建即可。 不過使用此方法時要注意改類影響的範圍,盡量不要在通用的類上執行此操作,否則會造成一些不可控的風險。
Java Class衝突定位思路