首页 > 解决方案 > 从调用者获取 ClassLoader 对象

问题描述

我已经使用 Java 中的 ResourceBundles 实现了插件机制和语言包。

如果我想ResourceBundle从核心程序(而不是插件)中获得一个,它工作得很好。

问题是我想添加在插件中创建一个ResourceBundle仅在插件内工作的可能性。

插件使用URLClassLoaders 和Reflections. ClassLoader我无法从翻译类访问(我不想) plugin 。因此,程序加载插件并稍后在插件内部执行一个方法(该插件不在类路径中)并且该插件执行 translate 方法。

为了实现这一点,我想从调用方法中获取 ClassLoader 对象。

这样这样的东西可能有用,但我看不到获取 Class/ClassLoader 而不是类名称的方法。

我以为我可以使用 Stacktrace 来获取调用方法的 ClassLoader,但我只能使用调用者的名称.getClassName和 noClassClassLoaderObject 来获取。

这就是我所拥有的:

翻译

public static String translate(Locale locale,String s) {
    for (ResourceBundle bundle : getResourceBundles(locale/*,Thread.currentThread().getStackTrace()[1].getClassLoader();*/)) {
        try {
            return bundle.getString(s);
        }catch (MissingResourceException e) {
            //ignore/next iteration
        }
    }
    return s;
}

获取资源包

private static Set<ResourceBundle> getResourceBundles(Locale locale,ClassLoader... loaders){
    Set<ResourceBundle> bundles=new HashSet<>();
    bundles.add(ResourceBundle.getBundle(BASE_NAME,locale,MyClass.class.getClassLoader()));
    for (ClassLoader loader : loaders) {
        ResourceBundle pluginBundle=getResourceBundle(g,loader);
        if (pluginBundle!=null) {
            bundles.add(pluginBundle);
        }
    }
    return bundles;
}

标签: javareflectionjava-8classloaderstack-trace

解决方案


我不认为这种反复试验的方法是一个好主意。也不是为每个字符串重新获取所有捆绑包。与让插件读取它们的包并调用它的替代方案相比,这个翻译服务似乎没有增加价值getString,至少不是一个可以证明代码的开销和复杂性的价值。

由于标准ResourceBundle.getBundle方法已经考虑了调用者的上下文,因此字段声明和获取表达式在放置在插件中并在其上调用时将是一个简单的单行器getString,并不比调用翻译服务的方法复杂。

为了完整起见,可以从 Java 9 开始以标准方式获取调用者类。然后,您可以这样做

private static final StackWalker STACK_WALKER
    = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

public static String translate(Locale locale, String s) {
    for(ResourceBundle bundle: getResourceBundles(locale,
                                   STACK_WALKER.getCallerClass().getClassLoader())) {
        try {
            return bundle.getString(s);
        }catch (MissingResourceException e) {
            //ignore/next iteration
        }
    }
    return s;
}

推荐阅读