2011-03-24 174 views
40

我加載了放置在./lib中的外部庫。這兩個解決方案是否設置java.library.path等效?在控制檯是-Djava.library.path = ...相當於System.setProperty(「java.library.path」,...)

  1. 設置路徑執行時,罐子:在代碼

    java -Djava.library.path=./lib -jar myApplication.jar 
    
  2. 設置路徑加載庫之前:

    System.setProperty("java.library.path", "./lib"); 
    

如果他們是等價,爲什麼在第二個解決方案中,Java可以找不到庫,而第一個可以嗎?

如果不是,有沒有辦法在代碼中設置路徑?

+0

'java.library.path'指*目錄*不是*文件* – jacktrades 2015-04-02 18:15:46

回答

44

一般而言,兩種方法的淨效應都相同,系統屬性java.library.path設置爲值./lib

但是,某些系統屬性僅在特定時間點進行評估,例如JVM的啓動。 如果java.library.path屬於這些屬性之一(並且您的實驗似乎表明了這一點),那麼使用第二種方法除了在將來的調用getProperty()上返回新值之外沒有明顯效果。

作爲一條經驗法則,使用-D命令行屬性適用於所有系統屬性,而System.setProperty()僅適用於不僅在啓動過程中進行檢查的屬性。

43

儘管沒有很好的文檔記錄,但就System.loadLibrary()方法而言,java.library.path系統屬性是「只讀」屬性。這是一個reported bug,但它被Sun關閉,而不是被修復。問題在於JVM的ClassLoader在啓動時讀取一次該屬性,然後將其緩存起來,不允許我們在之後以編程方式更改它。除System.getProperty()方法調用外,行System.setProperty("java.library.path", anyVal);將不起作用。

幸運的是,有人posted a workaround on the Sun forums。不幸的是,該鏈接不再有效,但我確實發現了the code on another source。這裏是你可以用它來解決不能夠設置java.library.path系統屬性的代碼:這可能不是在所有的平臺和/或JVM中工作:

public static void addDir(String s) throws IOException { 
    try { 
     // This enables the java.library.path to be modified at runtime 
     // From a Sun engineer at http://forums.sun.com/thread.jspa?threadID=707176 
     // 
     Field field = ClassLoader.class.getDeclaredField("usr_paths"); 
     field.setAccessible(true); 
     String[] paths = (String[])field.get(null); 
     for (int i = 0; i < paths.length; i++) { 
      if (s.equals(paths[i])) { 
       return; 
      } 
     } 
     String[] tmp = new String[paths.length+1]; 
     System.arraycopy(paths,0,tmp,0,paths.length); 
     tmp[paths.length] = s; 
     field.set(null,tmp); 
     System.setProperty("java.library.path", System.getProperty("java.library.path") + File.pathSeparator + s); 
    } catch (IllegalAccessException e) { 
     throw new IOException("Failed to get permissions to set library path"); 
    } catch (NoSuchFieldException e) { 
     throw new IOException("Failed to get field handle to set library path"); 
    } 
} 

警告。

+3

看看[這個較新的答案](http://stackoverflow.com/a/24988095/346561)@luyifan似乎完成與這個答案相同的東西,代碼少。 – 2015-08-24 16:34:42

32

您可以添加三行

System.setProperty("java.library.path", "/path/to/libs"); 
Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths"); 
fieldSysPath.setAccessible(true); 
fieldSysPath.set(null, null); 

,並導入java.lang.reflect.Field中 這是確定要解決的問題

+2

這個效果很好(比起Jesse Webb的解決方案,我們自己建造的溫度路徑要簡單) – 2014-08-13 13:31:02

+0

這是一個救生員。 Sun/Oracle似乎懶惰不提供從特定的,運行時定義的目錄加載庫的更直接方式。 – gromit190 2017-05-05 08:44:40