我使用 Java 中的 ResourceBundles 实现了插件机制和语言包。
如果我想从核心程序(而不是插件)获取ResourceBundle
,它工作得很好。
问题是我想添加创建插件中的 ResourceBundle
的可能性,并且仅在插件内工作。
插件使用URLClassLoader
和Reflections
加载。我无法从翻译类访问(我不想)插件 ClassLoader
。
因此,程序加载插件并稍后执行插件内的方法(插件不在类路径中),并且该插件执行翻译方法。
为了实现这一点,我想从调用方法中获取 ClassLoader 对象。
类似于 this或this可能有用,但我没有找到获取类/类加载器而不是类名称的方法。
我以为我可以使用 Stacktrace 来获取调用方法的 ClassLoader,但我只能使用 .getClassName
获取名称,而不能使用 Class
或 ClassLoader
调用者的对象。
这就是我所拥有的:
翻译
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;
}
最佳答案
我认为这种反复试验的方法不是一个好主意。也不是为每个字符串重新获取所有包。与仅让插件读取其 bundle 并调用 getString
的替代方案相比,该翻译服务似乎并没有增加任何值(value)。就其而言,至少没有一个可以证明代码的开销和复杂性的值。
自标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;
}
关于java - 从调用者获取 ClassLoader 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56636265/