我已经在Java中使用ResourceBundles实现了插件机制和语言包。
如果我想从核心程序(而不是从插件)获取ResourceBundle
,它工作得很好。
问题是我想添加创建插件中且仅在插件中工作的ResourceBundle
的可能性。
插件使用URLClassLoader
s 和Reflections
加载。我无法访问(我不想)翻译类中的插件ClassLoader
。 因此,程序加载插件并在稍后执行插件内部的方法(插件不在类路径中),并且该插件执行翻译方法。
为了存档这一点,我想从调用方法中获取类加载器对象。
像这样或这样的Somethng可能很有用,但我看不到获取Class/ClassLoader而不是类名称的方法。
我以为我可以使用 Stacktrace 来获取调用方法的类加载器,但我只能使用.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;
}
我不认为这种试错法是一个好主意。也不是为每个字符串重新获取所有捆绑包。这个翻译服务似乎并没有增加一个价值,而不是让插件读取他们的捆绑包并调用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;
}