问题描述:

I have a simple plugin system, that loads external JAR plugins into main application. I am using Mountainblade Modular to do so. Not sure how they do it "under the hood" but probably it's something standard.

This works fine, I instantiate classes from external jar and it all works. Except that some plugins come with icons/images. I am a bit unsure on how do I load/refer to images from that external JAR (with code inside that external JAR, as it is ran in context of the main JAR, kind of)

How should I approach this?

网友答案:

This issue is not as straightforward as it seems to be.

When you load classes from external jar, they are "loaded" into JVM. By "loading" into JVM I mean that JVM is responsible for their storage in memory. Usually it is done like this:

ClassLoader myClassLoader = new MyClassLoader(jarFileContent);
Class myExtClass = myClassLoader.loadClass(myClassName);

Resources from classpath jars can be accessed easily with

InputStream resourceStream = myClass.getResourceAsStream("/myFile.txt");

You can do that, because these jars are in classpath, I mean their location is known. These files are not stored in memory. When resource is accessed, JVM can search for it in classpath jars (for example on file system).

But for external jars it is completely different: jar comes from nowhere, is once processed and forgotten. JVM does not load resources from it in memory. In order to access these files, you have to manually organize their storage. I've done this once so I can share the code. It will help you to understand the basic idea (but probably won't help you with your specific library).

// Method from custom UrlClassLoader class. 
// jarContent here is byte array of loaded jar file.
// important notes:
// resources can be accesed only with this custom class loader
// resource content is provided with the help of custom URLStreamHandler 
@Override
protected URL findResource(String name) {       
    JarInputStream jarInputStream;
    try {
        jarInputStream = new JarInputStream(new ByteArrayInputStream(jarContent));
        JarEntry jarEntry;
        while (true) {
            jarEntry = jarInputStream.getNextJarEntry();
            if (jarEntry == null) {
                break;
            }
            if (name.equals(jarEntry.getName())) {
                final byte[] bytes = IOUtils.toByteArray(jarInputStream);
                return new URL(null, "in-memory-bytes", new URLStreamHandler() {
                    @Override
                    protected URLConnection openConnection(URL u) throws IOException {
                        return new URLConnection(u) {
                            @Override
                            public void connect() throws IOException {
                                // nothing to do here
                            }
                            @Override
                            public InputStream getInputStream() throws IOException {
                                return new ByteArrayInputStream(bytes);
                            }
                        };
                    }
                });
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
相关阅读:
Top