使用带有java反射的libpath

时间:2010-05-24 17:58:06

标签: java reflection java-native-interface

我正在动态加载一个类并在其上调用方法。这门课做JNI。当我调用该类时,java会尝试加载该库。这会导致错误,因为库不在libpath上。我正在从一个jar调用,所以我不能轻易改变libpath(特别是因为该库不在同一目录或jar的子目录中)。我知道库的路径,但是如何在加载类之前加载它。

当前代码:

public Class<?> loadClass(String name) throws ClassNotFoundException {
    if(!CLASS_NAME.equals(name))
            return super.loadClass(name);

    try {
        URL myUrl = new URL(classFileUrl);
        URLConnection connection = myUrl.openConnection();
        InputStream input = connection.getInputStream();
        byte[] classData = readConnectionToArray(input);

        return defineClass(CLASS_NAME,
                classData, 0, classData.length);

    } catch (MalformedURLException e) {
        throw new UndeclaredThrowableException(e);
    } catch (IOException e) {
        throw new UndeclaredThrowableException(e); 
    }
}

例外:

Can't find library libvcommon.so
java.lang.UnsatisfiedLinkError: vcommon (A file or directory in the path name does not exist.)
        at java.lang.ClassLoader.loadLibraryWithPath(ClassLoader.java:998)
        at java.lang.ClassLoader.loadLibraryWithClassLoader(ClassLoader.java:962)
        at java.lang.System.loadLibrary(System.java:465)
        at vcommon.(vcommon.java:103)
        at java.lang.J9VMInternals.initializeImpl(Native Method)
        at java.lang.J9VMInternals.initialize(J9VMInternals.java:200)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
        at java.lang.reflect.Method.invoke(Method.java:599)
        at com.fortune500.fin.v.vunit.reflection.ReflectionvProcessor.calculateV(ReflectionvProcessor.java:36)
        at com.fortune500.fin.v.vunit.UTLTestCase.execute(UTLTestCase.java:42)
        at com.fortune500.fin.v.vunit.TestSuite.execute(TestSuite.java:15)
        at com.fortune500.fin.v.vunit.batch.Testvendor.execute(Testvendor.java:101)
        at com.fortune500.fin.v.vunit.batch.Testvendor.main(Testvendor.java:58)

编辑:我现在有64位对32位的问题。当我把它整理出来时,我会回到这里。

  

相关:Dynamic loading a class in java with a different package name

1 个答案:

答案 0 :(得分:1)

如果您知道库的路径,则可以在自定义类加载器中添加java.library.path环境变量的路径。一种更简单的方法是计算路径并在调用Runtime.loadLibrary时使用它。

下面的代码概述了两种方法,使用loadLibrary并设置java.library.path系统属性。

 if(CLASS_NAME.equals(name)) {

    // two ways of doing this - either load the library explicitly from the full path  
    if (useFullPath) {
      Runtime.getRuntime().loadLibrary("/full/path/to/mylibrary");
    }
    else { // or tweaking the library path
      System.setProperty("java.library.path", 
         System.getProperty("java.library.path")
         + System.getProperty("file.separator")
         + "/path/to/lib");
    }
 }
 return super.loadClass(name);

你提到你的代码是从jar中调用的 - 如果ClassLoader也是jar的一部分,使用自定义类加载器会很困难。你确认你的类加载器确实被使用了吗?

更简单的方法是将当前调用更改为本机类中的loadLibrary以使用完整路径。例如。如果您事先知道在哪里找到它,请从系统属性中获取或计算它。当然,如果您拥有本机类的源代码,那么这只是一个选项。如果您无法修改本机类,请在类加载器中使用loadLibrary调用。

我的理解是,使用相同库名称(无论路径)加载库的调用加载相同的库。 (至少,这是Windows上的行为 - 我还没有在Linux上验证。)因此,即使类加载器使用完整路径加载库,并且本机类使用它的简单名称加载库,两者都应解析为同一个图书馆。

(只是为了完整性,在内核中解析等效的库,再次说,从Win32的经验来看。每个库内部都有一个名称,而windows只加载一个库的一个实例,每个进程具有相同的内部名称。)