繁体   English   中英

在初始化静态对象之前,如何使Classloader评估类路径?

[英]How to Make a Classloader evaluate the classpath before initlializing static objects?

我有一个正在开发的应用程序,它同时使用jar库和本机系统库。 我的问题是默认的类加载器会在调用main之前很久就尝试加载静态类。 由于类路径尚未包含静态类所需的本机库,因此在第一个评估的静态引用处将引发java.lang.NoClassDefFoundError。

这是我无法访问的库加载方法的样子:

private static void load_libraries() {
    try {
        String osname = getOSName();

        if (osname == null) {
            throw new RuntimeException("The system you are running on is not supported");
        }
        URL u = NativeLibs.class.getResource(osname);

        URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Class urlClass = URLClassLoader.class;
        Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
        method.setAccessible(true);
        method.invoke(urlClassLoader, new Object[]{u});
    } catch (IllegalAccessException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
    } catch (IllegalArgumentException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
    } catch (InvocationTargetException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
    } catch (NoSuchMethodException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
    } catch (SecurityException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
    }

}

所以,让我解释一下这是怎么回事。 首先,getOSName()所做的所有操作都是返回一个表示我正在运行的OS系列的字符串。 如果操作系统不受支持,则返回null。 万一我在该方法上遇到问题,我将继续进行发布:

private static String getOSName() {
    String os = System.getProperty("os.name").toLowerCase(Locale.US);
    if (os.indexOf("win") >= 0) {
        return "windows";
    } else if (os.indexOf("mac os x") >= 0) {
        return "macosx";
    } else if (os.indexOf("nux") >= 0) {
        return "linux";
    } else if (os.indexOf("solaris") >= 0) {
        return "solaris";
    } else {
        return null;
    }
}

它返回的字符串是目录名,方法load_libraries()使用该目录名定义一个相对URL,我以反射方式传递给类加载器以加载库。 我的问题是,即使这是main中的第一个方法,运行时执行也永远不会到达load_libraries()。

一种显而易见的解决方案是使用自定义的jar静态地加载本机库。 我根本不想静态链接本机库,因为这违背了Java平台可移植性的目的。 我已经推断出的另一个解决方案是一个系统可执行文件,它可以使用来自系统可执行文件的确定的自动类路径来运行应用程序jar,但是该解决方案仍需要多个特定于平台的可执行文件。

所以,这是我的问题:

我可以强制类加载器在初始化静态对象之前运行我的库加载方法吗? 这是否需要定制的ClassLoader? 如果确实需要自定义ClassLoader,是否只需传递代表默认Classloader的系统属性即可解决此问题?

谢谢,我希望我写了足够详细的问题!

“默认类加载器会在调用main之前很久就尝试加载静态类”的原因是因为您的主类具有静态成员变量和/或静态初始化器。 当类加载器初始化您的主类时,它还必须初始化这些静态变量。 有关更多信息,请参见VM Spec

解决方案(唯一的方法)是消除静态初始化。 main()初始化静态成员变量,或使用诸如Spring之类的框架进行初始化。

通常,静态成员变量很少有很好的用途。 他们中的大多数最终都是黑客,他们可以从程序中的任意位置访问资源。 这不仅使程序更难测试,而且导致意外的初始化链。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM