简体   繁体   English

使用SPI加载时消失的jar条目

[英]Disappearing jar entry when loading using SPI

So in my application I have a plugin system that I've written using SPI (service provider interface), so I have a jar file called scripts.jar that I keep somewhere (note: it's not on the classpath), then I load a script from it using this method: 所以在我的应用程序中我有一个插件系统,我用SPI(服务提供程序接口)编写,所以我有一个名为scripts.jar的jar文件,我保留在某处(注意:它不在类路径上),然后我加载一个使用此方法的脚本:

/**
 * Loads a script from the given name, regardless of case.
 * @param name script name
 * @return the loaded Script
 */
public static Script loadScript(Client c, String name) {
    Script script = null;
    try {
        URLClassLoader loader = new URLClassLoader(new URL[]{new File(Config.CONF_DIR, "scripts.jar").toURI().toURL()});
        ServiceLoader serviceLoader = ServiceLoader.load(Script.class, loader);
        serviceLoader.reload();
        Iterator<Script> scripts = serviceLoader.iterator();
        while(scripts.hasNext()) {
            Script cur = scripts.next();
            if(cur.getClass().getSimpleName().equalsIgnoreCase(name)) {
                script = cur;
                break;
            }
        }
    } catch(Exception e) {
        log.warn("Error loading script "+name, e);
    }
    return script;
}

Now, this works fantastically when I start my program. 现在,当我开始我的程序时,这非常有效。 I can load any script in the jar with ease. 我可以轻松地在jar中加载任何脚本。

The problem arises when I reload the script - ie change the file, and overwrite scripts.jar, then try to load any script. 当我重新加载脚本时出现问题 - 即更改文件,并覆盖scripts.jar,然后尝试加载任何脚本。 I get this error: 我收到此错误:

    Exception in thread "anjin_san:test" java.util.ServiceConfigurationError: org.stork.script.Script: Error reading configuration file
        at java.util.ServiceLoader.fail(ServiceLoader.java:207)
        at java.util.ServiceLoader.parse(ServiceLoader.java:284)
        at java.util.ServiceLoader.access$200(ServiceLoader.java:164)
        at java.util.ServiceLoader$LazyIterator.hasNext(ServiceLoader.java:332)
        at java.util.ServiceLoader$1.hasNext(ServiceLoader.java:415)
        at org.stork.script.Script.loadScript(Script.java:408)
        at org.stork.Client$2.run(Client.java:95)
        at java.lang.Thread.run(Thread.java:619)
Caused by: java.io.FileNotFoundException: JAR entry META-INF/services/org.stork.script.Script not found in C:\Users\stork\Documents\bot-sama\etc\scripts.jar
        at sun.net.www.protocol.jar.JarURLConnection.connect(JarURLConnection.java:122)
        at sun.net.www.protocol.jar.JarURLConnection.getInputStream(JarURLConnection.java:132)
        at java.net.URL.openStream(URL.java:1010)
        at java.util.ServiceLoader.parse(ServiceLoader.java:279)
        ... 6 more

So it says the jar entry can't be found, but I can check it's there fairly easily: 所以它说无法找到jar条目,但我可以很容易地检查它:

    C:\Users\stork\Documents\bot-sama\etc>jar tvf scripts.jar
     0 Thu Sep 03 16:58:00 BST 2009 META-INF/
   102 Thu Sep 03 16:57:58 BST 2009 META-INF/MANIFEST.MF
     0 Thu Sep 03 16:35:20 BST 2009 META-INF/services/
   482 Thu Sep 03 16:57:52 BST 2009 META-INF/services/org.stork.script.Script
   ...

And it's the right size, too. 它也是合适的尺寸。 The problem happens when I try to load any script, not just the one that was modified. 当我尝试加载任何脚本时,问题就发生了,而不仅仅是修改过的脚本。

I'm thinking this might be a bug, any input? 我想这可能是一个错误,任何输入?

Check the file permissions. 检查文件权限。 When the original JAR is placed there with the rest of the application, it is readable by the program. 当原始JAR与应用程序的其余部分放在一起时,程序可以读取它。 Perhaps its being updated by a different user—without granting read permissions to other users—and the program can no longer open the file. 也许它由不同的用户更新 - 而不向其他用户授予读取权限 - 并且程序无法再打开该文件。

I can't tell which version of Windows you are running, but the security properties dialog or, on XP Home, the cacls command should detail the permissions before and after. 我无法分辨您正在运行的Windows版本,但安全属性对话框,或者在XP Home上, cacls命令应详细说明之前和之后的权限。


Update: Re-reading the ServiceLoader documentation, I noticed an instance method, reload . 更新:重新阅读ServiceLoader文档,我注意到了一个实例方法, reload Although the code creates a new ServiceLoader each time it's needed, it may be that the ServiceLoader class is keeping a cache that is used by all instances. 虽然代码每次需要时都会创建一个新的ServiceLoader ,但可能是ServiceLoader类保留了所有实例使用的缓存。 Rather than creating new loaders, try keeping one around, and using the reload method to check for new scripts. 而不是创建新的加载器,尝试保持一个,并使用reload方法来检查新的脚本。

As a comment in another answer says, disabling the caching in the URLconnection worked for me, but in my solution I don't call the openConnection() method. 正如另一个答案中评论所说,禁用URL连接中的缓存对我有用,但在我的解决方案中,我没有调用openConnection()方法。 Instead, I call following method: 相反,我称之为以下方法:

private void disableURLConnectionCache() {

    new URLConnection(null) {
        @Override
        public void connect() throws IOException {}
    }.setDefaultUseCaches(false);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM