2016-03-05 73 views
0

我有一個PluginManager類手錶./plugins目錄使用WatchService文件創建,然後從PluginLoader類在運行時加載新添加的罐子採用靜態方法loadPlugin(File)。文件夾中的所有jar也會在應用程序啓動時加載並啓動,在這種情況下,即使插入一堆插件,情況也會一切順利。
但是當我通過一個拖放插件到該文件夾​​一個,我得到一個奇怪的現象:只有5%左右的時間 熱負荷.jar文件:隨機FileNotFoundException異常

  • 第二98%

    • 第一罐子裝精
    • 第三隻在非常罕見的情況下,但它發生

    我所得到的是這樣的:

    java.io.FileNotFoundException: .\plugins\test2.jar (Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird) 
    at java.util.zip.ZipFile.open(Native Method) 
    at java.util.zip.ZipFile.<init>(ZipFile.java:220) 
    at java.util.zip.ZipFile.<init>(ZipFile.java:150) 
    at java.util.jar.JarFile.<init>(JarFile.java:166) 
    at java.util.jar.JarFile.<init>(JarFile.java:130) 
    at PluginLoader.loadPlugin(PluginLoader.java:34) 
    at PluginManager$WatchQueueReader.run(PluginManager.java:118) 
    at java.lang.Thread.run(Thread.java:745) 
    Exception in thread "FileWatcher" java.lang.NullPointerException 
    at PluginLoader.loadPlugin(PluginLoader.java:41) 
    at PluginManager$WatchQueueReader.run(PluginManager.java:118) 
    at java.lang.Thread.run(Thread.java:745) 
    

    這是說該文件在另一個進程中使用。

    插件加載:

    public static BasePlugin loadPlugin(File pluginJar) { 
        Attributes attrib = null; 
        JarFile file = null; 
        try { 
         file = new JarFile(pluginJar); 
         Manifest manifest = file.getManifest(); 
         attrib = manifest.getMainAttributes(); 
        } catch (IOException e) { 
         e.printStackTrace(); 
        } 
    
        String main = attrib.getValue(Attributes.Name.MAIN_CLASS); 
        String name = attrib.getValue("Plugin-Name"); 
    
        if (main == null || name == null) { 
         System.out.println("Not a valid manifest: " + pluginJar.getName()); 
         return null; 
        } 
    
        URLClassLoader loader = null; 
        try { 
         loader = URLClassLoader.newInstance(new URL[] { pluginJar.toURI().toURL() }, PluginLoader.class.getClassLoader()); 
        } catch (MalformedURLException e2) { 
         e2.printStackTrace(); 
        } 
        Class<?> cl = null; 
        try { 
         cl = Class.forName(main, true, loader); 
        } catch (ClassNotFoundException e1) { 
         e1.printStackTrace(); 
        } finally { 
         try { 
          loader.close(); 
         } catch (IOException e) { 
          e.printStackTrace(); 
         } 
        } 
    
        try { 
         Class<? extends BasePlugin> c = cl.asSubclass(BasePlugin.class); 
         Constructor<? extends BasePlugin> ctr = c.getConstructor(String.class, SystemManager.class); 
         return ctr.newInstance(name, this.sm); 
        } catch (Exception e) { 
         e.printStackTrace(); 
        } 
        return null; 
    } 
    

    WatchService內插件管理:

    private static class WatchQueueReader implements Runnable { 
    
        private WatchService watcher; 
        private PluginManager pm; 
    
        public WatchQueueReader(PluginManager pm, WatchService watcher) { 
         this.pm = pm; 
         this.watcher = watcher; 
        } 
    
        @Override 
        public void run() { 
         try { 
          WatchKey key = watcher.take(); 
          while (key != null) { 
           for (WatchEvent<?> event : key.pollEvents()) { 
            switch (event.kind().toString()) { 
            case "ENTRY_CREATE": 
             Path dir = (Path) key.watchable(); 
             Path fullPath = dir.resolve(event.context().toString()); 
             BasePlugin plugin = PluginLoader.loadPlugin(fullPath.toFile()); 
             if (plugin != null) { 
              this.pm.startPlugin(plugin); 
             } 
             break; 
            case "ENTRY_MODIFY": 
             break; 
            case "ENTRY_DELETE": 
             this.pm.stopPlugin(event.context().toString()); // TODO wrong name (.jar) 
             break; 
            default: 
             break; 
            } 
           } 
           key.reset(); 
           key = watcher.take(); 
          } 
         } catch (InterruptedException e) { 
          e.printStackTrace(); 
         } 
        } 
    } 
    

    BasePlugin是一個抽象類,插件擴展。

  • 回答

    1

    該文件仍在複製,WatchService只是發現它太快。實際上,只要創建了[inode],但它還沒有被填充信息(字節,你知道),它就會立即報告文件存在。

    我的第一個提示是,如果遇到此異常,請等待幾秒鐘,然後重試。就在10-30秒的無用嘗試之後,你可以放棄,因爲它可能已被刪除。但是這部分需要微調,因爲複製操作可能很慢。

    +0

    謝謝,那就是問題所在。也許可以在ENTRY_CREATE之後等待ENTRY_MODIFY? – Benjoyo

    +1

    我不確定。該文檔說:「當報告某個事件表明已監視目錄中的文件已被修改時,則不能保證已修改該文件的程序(或程序)已完成。」 – Koshinae