如何获取已加载的JNI库列表?

正如主题所说的那样,Java中是否有一种方法可以获得在任何给定时间加载的所有JNI本机库的列表?

如果你的意思是,有一种方法可以确定所有当前加载的本机库。 已经卸载的库无法确定。

基于Svetlin Nakov( 在JVM中加载到单个JAR的Extract类 )的工作,我做了一个POC,它给你从应用程序类加载器和当前类的类加载器加载的本机库的名称。

首先是没有bu的简化版本….它处理exception,错误消息,javadoc,….

获取类加载器通过reflection存储已加载库的私有字段

public class ClassScope { private static final java.lang.reflect.Field LIBRARIES; static { LIBRARIES = ClassLoader.class.getDeclaredField("loadedLibraryNames"); LIBRARIES.setAccessible(true); } public static String[] getLoadedLibraries(final ClassLoader loader) { final Vector libraries = (Vector) LIBRARIES.get(loader); return libraries.toArray(new String[] {}); } } 

像这样打电话给上面

 final String[] libraries = ClassScope.getLoadedClasses(ClassLoader.getSystemClassLoader()); //MyClassName.class.getClassLoader() 

voilá libraries保存已加载的本机库的名称。

从这里获取完整的源代码

我已经建立在抖动解决方案之上。 这允许您找出加载每个本机库的人(ClassLoader,Class)。

 import java.lang.reflect.Field; import java.util.*; import java.util.Map.Entry; /** * Helper functions for native libraries. * 

* @author Gili Tzabari */ public class NativeLibraries { private final Field loadedLibraryNames; private final Field systemNativeLibraries; private final Field nativeLibraries; private final Field nativeLibraryFromClass; private final Field nativeLibraryName; /** * Creates a new NativeLibraries. *

* @throws NoSuchFieldException if one of ClassLoader's fields cannot be found */ public NativeLibraries() throws NoSuchFieldException { this.loadedLibraryNames = ClassLoader.class.getDeclaredField("loadedLibraryNames"); loadedLibraryNames.setAccessible(true); this.systemNativeLibraries = ClassLoader.class.getDeclaredField("systemNativeLibraries"); systemNativeLibraries.setAccessible(true); this.nativeLibraries = ClassLoader.class.getDeclaredField("nativeLibraries"); nativeLibraries.setAccessible(true); Class nativeLibrary = null; for (Class nested : ClassLoader.class.getDeclaredClasses()) { if (nested.getSimpleName().equals("NativeLibrary")) { nativeLibrary = nested; break; } } this.nativeLibraryFromClass = nativeLibrary.getDeclaredField("fromClass"); nativeLibraryFromClass.setAccessible(true); this.nativeLibraryName = nativeLibrary.getDeclaredField("name"); nativeLibraryName.setAccessible(true); } /** * Returns the names of native libraries loaded across all class loaders. *

* @return a list of native libraries loaded */ public List getLoadedLibraries() { try { @SuppressWarnings("UseOfObsoleteCollectionType") final Vector result = (Vector) loadedLibraryNames.get(null); return result; } catch (IllegalArgumentException | IllegalAccessException e) { throw new AssertionError(e); } } /** * Returns the native libraries loaded by the system class loader. *

* @return a Map from the names of native libraries to the classes that loaded them */ public Map> getSystemNativeLibraries() { try { Map> result = new HashMap<>(); @SuppressWarnings("UseOfObsoleteCollectionType") final Vector libraries = (Vector) systemNativeLibraries.get(null); for (Object nativeLibrary : libraries) { String libraryName = (String) nativeLibraryName.get(nativeLibrary); Class fromClass = (Class) nativeLibraryFromClass.get(nativeLibrary); result.put(libraryName, fromClass); } return result; } catch (IllegalArgumentException | IllegalAccessException e) { throw new AssertionError(e); } } /** * Returns a Map from the names of native libraries to the classes that loaded them. *

* @param loader the ClassLoader that loaded the libraries * @return an empty Map if no native libraries were loaded */ public Map> getNativeLibraries(final ClassLoader loader) { try { Map> result = new HashMap<>(); @SuppressWarnings("UseOfObsoleteCollectionType") final Vector libraries = (Vector) nativeLibraries.get(loader); for (Object nativeLibrary : libraries) { String libraryName = (String) nativeLibraryName.get(nativeLibrary); Class fromClass = (Class) nativeLibraryFromClass.get(nativeLibrary); result.put(libraryName, fromClass); } return result; } catch (IllegalArgumentException | IllegalAccessException e) { throw new AssertionError(e); } } /** * The same as {@link #getNativeLibraries()} except that all ancestor classloaders are processed * as well. *

* @param loader the ClassLoader that loaded (or whose ancestors loaded) the libraries * @return an empty Map if no native libraries were loaded */ public Map> getTransitiveNativeLibraries(final ClassLoader loader) { Map> result = new HashMap<>(); ClassLoader parent = loader.getParent(); while (parent != null) { result.putAll(getTransitiveNativeLibraries(parent)); parent = parent.getParent(); } result.putAll(getNativeLibraries(loader)); return result; } /** * Converts a map of library names to the classes that loaded them to a map of library names to * the classloaders that loaded them. *

* @param libraryToClass a map of library names to the classes that loaded them * @return a map of library names to the classloaders that loaded them */ public Map getLibraryClassLoaders(Map> libraryToClass) { Map result = new HashMap<>(); for (Entry> entry : libraryToClass.entrySet()) result.put(entry.getKey(), entry.getValue().getClassLoader()); return result; } /** * Returns a list containing the classloader and its ancestors. *

* @param loader the classloader * @return a list containing the classloader, its parent, and so on */ public static List getTransitiveClassLoaders(ClassLoader loader) { List result = new ArrayList<>(); ClassLoader parent = loader.getParent(); result.add(loader); while (parent != null) { result.add(parent); parent = parent.getParent(); } return result; } }

由于Nicolas提到了Scala,这里是通过JRuby进行抖动解决方案的一种方法(在1.6和1.7中测试):

 require 'java' import 'java.lang.ClassLoader' f = ClassLoader.java_class.declared_field('loadedLibraryNames') f.accessible = true f.value(ClassLoader.system_class_loader).to_array.to_a 

FWIW,这是抖动的解决方案 ,这次是一个小的Scala方法:

 def loadedLibs: Seq[String] = { val libs = classOf[ClassLoader].getDeclaredField("loadedLibraryNames") libs.setAccessible(true) import scala.collection.JavaConverters._ libs.get(ClassLoader.getSystemClassLoader()) .asInstanceOf[java.util.Vector[String]] .asScala } 

在Clojure中,在REPL复制/管理:

 (-> (doto (.getDeclaredField ClassLoader "loadedLibraryNames") (.setAccessible true)) (.get (ClassLoader/getSystemClassLoader))) 

在Groovy中(在2.3.3中测试):

 libs = ClassLoader.class.getDeclaredField("loadedLibraryNames") libs.setAccessible(true) libraries = libs.get(ClassLoader.getSystemClassLoader())