【问题标题】:How to load ResourceBundles within loaded JAR如何在加载的 JAR 中加载 ResourceBundles
【发布时间】: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


【解决方案1】:

我发现在 PluginManagerImpl 的 loadPlugin 中关闭 URLClassLoader(作为自动关闭)导致了问题。 尝试使用该 URLClassLoader 加载资源,如果它关闭,它将失败。 如果 URLClassLoader 根本没有关闭,会发生什么效果?据我了解,由于 JarFile 未关闭,这可能会产生负面影响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-14
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    • 2012-09-08
    • 1970-01-01
    • 2011-05-26
    相关资源
    最近更新 更多