【发布时间】:2022-08-14 04:10:11
【问题描述】:
我在加载的 jar 中加载资源包时遇到问题。主程序是从一个带有插件管理器的文件夹中加载 jars。当插件管理器初始化jar的主类的对象时,可以加载该jar的资源包。我的意思是在静态块或构造函数中。否则,将引发 MissingResourceException。就像您在该对象上调用一个方法时一样,它会尝试加载现有的资源包
目前,我在 jar 的主类的开头使用一个静态块来加载插件的所有资源包以及可能的语言环境。因此,资源包将被缓存一段时间。此外,我目前的方式似乎适用于子加载的罐子,就像加载的罐子一样
public class PluginMain implements PluginInterface {
static {
for (Locale availableLocale : getAvailableLocales()) {
try {
ResourceBundle resourceBundle = ResourceBundle.getBundle(BUNDLE_PATH, availableLocale);
} catch (MissingResourceException e) {
e.printStackTrace();
}
}
}
...
}
我认为这是关于加载资源包的类加载器。我仍然找不到一个好的解决方案。 我已经尝试找到一些解决方案。我能找到的最合适的是Loading with ResourceBundle from inside a jar,但这并没有成功。
编辑:我像这样加载我的罐子
public class PluginManagerImpl implements PluginManager {
private final List<PluginInterface> loadedPlugins = new ArrayList<>();
private final String path;
public PluginManagerImpl(String path) {
File pluginsDir = new File(path, \"plugins\");
this.path = pluginsDir.getPath();
if (pluginsDir.exists()) {
//pluginsfolder exists
File[] files = pluginsDir.listFiles();
if (files != null) {
for (File f : files)
if (!f.isDirectory()) {
loadPlugin(f);
}
}
} else {
//pluginsfolder does not exist
if (pluginsDir.mkdir()) {
Output.WriteLine(\"Dictionary created: \" + pluginsDir.getPath());
}
}
}
@Override
public void loadPlugin(File file) {
URL urlFile;
//trying to load file, convert it first to URI and then to URL
try {
urlFile = file.toURI().toURL();
} catch (MalformedURLException e) {
Output.WriteLineProblem(e.getMessage(), 4);
return;
}
//trying to create JAR-file from file
try (
//use JarFIle and URLClassLoader as auto-closable
JarFile jarFile = new JarFile(file);
//use classloader of this class as parent classLoader
URLClassLoader classLoader = new URLClassLoader(new URL[]{urlFile}, this.getClass().getClassLoader())
) {
//load manifest
Manifest manifest = jarFile.getManifest();
//read attributes from manifest
Attributes attributes = manifest.getMainAttributes();
//get main class from attributes
String main = attributes.getValue(Attributes.Name.MAIN_CLASS);
if (main == null) {
Output.WriteLineProblem(file.getName() + \" has no main specified\");
return;
}
String title = attributes.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
if (title == null) {
//https://maven.apache.org/shared/maven-archiver/index.html
Output.WriteLineProblem(file.getName() + \" has no implementation title specified\");
return;
}
//https://javapapers.com/core-java/java-class-loader/
//load class with classLoader of jarFile
Class<?> cl = classLoader.loadClass(main);
//get implemented interfaces of class
Class<?>[] interfaces = cl.getInterfaces();
//iterate over interfaces and check for PluginInterface.class
boolean isPlugin = false;
for (Class<?> anInterface : interfaces) {
if (anInterface.equals(PluginInterface.class)) {
isPlugin = true;
break;
}
}
if (isPlugin) {
//load all classes in jar file
loadClassesOfjarFile(jarFile, cl.getClassLoader());
//add the pluginfile
PluginInterface plugin = (PluginInterface) cl.getConstructor().newInstance();
plugin.calledAfterInstancing(new File(path, title).getPath());
Output.WriteLine(\"Loaded Plugin \" + title);
loadedPlugins.add(plugin);
}
} catch (Exception e) {
Output.WriteLineProblem(\"Error on checking \" + file.getName() + \" for plugin\");
e.printStackTrace();
}
}
public static void loadClassesOfjarFile(JarFile jarFile, ClassLoader classLoader) {
jarFile.entries().asIterator().forEachRemaining(jarEntry -> {
String jarEntryName = jarEntry.getName();
if ((jarEntryName.endsWith(\".class\"))) {
String className = jarEntry.getName().replaceAll(\"/\", \"\\\\.\");
String myClass = className.substring(0, className.lastIndexOf(\'.\'));
try {
Class<?> clazz = classLoader.loadClass(myClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
} else if (jarEntryName.endsWith(\".xml\")) {
String resourceName = jarEntry.getName().replaceAll(\"/\", \"\\\\.\");
classLoader.getResourceAsStream(jarEntry.getName());
}
});
}
}
编辑 2:Here a sample project to test 资源包包含在插件的资源文件夹中。 Hierarchy of the project
主程序示例:
package main;
public class Main {
public static final String DEFAULT_PATH = FileSystems.getDefault().getPath(\"\").toAbsolutePath().toString();
public static void main(String[] args) {
PluginManager plugins = new PluginManager(DEFAULT_PATH);
List<PluginInterface> loadedPlugins = plugins.getLoadedplugins();
for (PluginInterface loadedPlugin : loadedPlugins) {
loadedPlugin.loadResourceBundle(Locale.ENGLISH);
}
}
}
插件示例:
package plugin;
public class Main implements PluginInterface {
static {
Locale locale = Locale.ENGLISH;
ResourceBundle main = ResourceBundle.getBundle(\"mainLoadedInStatic\", locale);
//only uncomment to check, that it would work if loaded in static
// ResourceBundle mainNotLoadedInStatic = ResourceBundle.getBundle(\"mainNotLoadedInStatic\", locale);
}
@Override
public void loadResourceBundle(Locale locale) {
ResourceBundle mainLoadedInStatic = ResourceBundle.getBundle(\"mainLoadedInStatic\", locale);
ResourceBundle mainNotLoadedInStatic = ResourceBundle.getBundle(\"mainNotLoadedInStatic\", locale);
}
}
错误应该是:
Exception in thread \"main\" java.util.MissingResourceException: Can\'t find bundle for base name mainNotLoadedInStatic, locale en
at java.base/java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:2045)
at java.base/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1683)
at java.base/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1586)
at java.base/java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:1549)
at java.base/java.util.ResourceBundle.getBundle(ResourceBundle.java:932)
at plugin.Main.loadResourceBundle(Main.java:19)
at main.Main.main(Main.java:18)
-
你能解释一下吗:
The main programm is loading plugins from a folder with a pluginmanager更详细地说你的意思是什么?你说的是Maven插件??? -
我的意思是我的主程序可以使用单独的编译 jar 来添加功能。我添加了加载插件的类的代码。
-
你的主要程序是什么?我们在谈论一个 Maven 插件吗?请详细说明...最好是一个完整的工作示例...
-
我已经重写了我的问题。也许现在我的意思更清楚了。
标签: java plugins resourcebundle