JNI, loading native libraries. Change java.library.path on the fly
This property is set once, before starting the JVM, through global system properties, or as the -Dname = value switch for the JVM, and after that it becomes read-only. More precisely, you can change it, but it will not have any effect on the program’s work, because after you update this property, the JVM will not reread it and will not use the new value.
Under the cut - about how to still change this property in runtime, and a little about how actually loading native libraries in Java works.
However, the ability to change java.library.path on the fly would be very helpful - then you would not have to generate, rewrite and rewrite scripts to run JBoss-a many times, for example, to reflect all the necessary paths BEFORE the app server starts.
And there is such an opportunity to change these ways in which the JVM searches for native libraries. Specific techniques are shown here - blog.cedarsoft.com/2010/11/setting-java-library-path-programmatically and also here - nicklothian.com/blog/2008/11/19/modify-javalibrarypath-at-runtime .
And here I will describe the loading mechanism itself, and for some reason, what is described by the links works. Typically, native libraries are loaded through a static initializer:
static {
try {
System.loadLibrary(«dp-integ»);
}
}
* This source code was highlighted with Source Code Highlighter.Which looks like this:
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(getCallerClass(), libname);
}
* This source code was highlighted with Source Code Highlighter.And further in the Runtime class:
synchronized void loadLibrary0(Class fromClass, String libname) {
// Проверяем, разрешено ли загружать данную конкретную библиотеку
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkLink(libname);
}
if (libname.indexOf((int)File.separatorChar) != -1) {
throw new UnsatisfiedLinkError("Directory separator" +
"should not appear in library name: " + libname);
}
ClassLoader.loadLibrary(fromClass, libname, false);
}
* This source code was highlighted with Source Code Highlighter.Those. in the end, native libraries are loaded, like regular classes, through ClassLoader. The ClassLoader class has two properties in which the initialized search paths are cached.
// The paths searched for libraries
static private String usr_paths[];
static private String sys_paths[];
* This source code was highlighted with Source Code Highlighter.The code of the ClassLoader.loadLibrary method (fromClass, libname, false), quite long, and cluttered with numerous checks, looks like this in abbreviated form.
// Invoked in the java.lang.Runtime class to implement load and loadLibrary.
static void loadLibrary(Class fromClass, String name,
boolean isAbsolute) {
ClassLoader loader = (fromClass == null) ? null : fromClass.getClassLoader();
if (sys_paths == null) {
// это то, что нам нужно
usr_paths = initializePath("java.library.path");
// а это для тех библиотек, которые загружаются из классов,
// загруженных из boot classpath.
sys_paths = initializePath("sun.boot.library.path");
}
// Дальше попытка загрузить библиотеку, и дальше,
// если найти ее так и не удалось, то -
// Oops, it failed
throw new UnsatisfiedLinkError("no " + name + " in java.library.path");
}
* This source code was highlighted with Source Code Highlighter.Thus, now the loading mechanism of the native library has become more clear.
You can either set the sys_paths property of the classloader to null, or simply change the sys_paths / usr_paths properties, adding the necessary paths to your native libraries to them.