2017-10-21 139 views
0

試圖爲我的應用程序實現插件系統,其代碼擴展了我的Plugin類以定義自定義功能。如何從運行時從工作目錄加載.class從jar?

此代碼從一個jar文件里加載一個類,在同一目錄作爲應用程序的的.jar,做工精細:

if(pluginName.endsWith(".jar")) 
{ 
    JarFile jarFile = new JarFile(pluginName); 
    Enumeration jarComponents = jarFile.entries(); 

    while (jarComponents.hasMoreElements()) 
    { 
     JarEntry entry = (JarEntry) jarComponents.nextElement(); 
     if(entry.getName().endsWith(".class")) 
     { 
      className = entry.getName(); 
     } 
    } 

    File file = new File(System.getProperty("user.dir")+"/"+pluginName); 
    URLClassLoader loader = new URLClassLoader(new URL[]{file.toURI().toURL()}); 

    Class newClass = Class.forName(className.replace(".class", ""), true, loader); 
    newPlugin = (Plugin) newClass.newInstance(); 
} 

導致的正確響應:

benpalmer$ java -jar assignment.jar test_subproject.jar 
- INFO: Add new plugin: source.com 

問題是我也想提供給用戶指定一個.class文件的選項,因爲這實際上是所有打包到.jar中用於我的插件系統的目的。

else if(pluginName.endsWith(".class")) 
{ 
    File file = new File(System.getProperty("user.dir")+"/"+pluginName); 
    URLClassLoader loader = new URLClassLoader(new URL[]{file.toURI().toURL()}); 

    Class newClass = Class.forName(className.replace(".class", ""), true, loader); 
    newPlugin = (Plugin) newClass.newInstance(); 
} 
... exception handling 

導致以下:

benpalmer$ java -jar assignment.jar TestPlugin.class 
SEVERE: Error: Plugin class not found. Class name: 
java.lang.ClassNotFoundException: 
    at java.lang.Class.forName0(Native Method) 
    at java.lang.Class.forName(Class.java:348) 
    at newsfeed.model.Plugin.loadClassFromJarFile(Plugin.java:144) 
    at newsfeed.controller.NFWindowController.initPlugins(NFWindowController.java:81) 
    at newsfeed.controller.NewsFeed$1.run(NewsFeed.java:20) 
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311) 
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756) 
    at java.awt.EventQueue.access$500(EventQueue.java:97) 
    at java.awt.EventQueue$3.run(EventQueue.java:709) 
    at java.awt.EventQueue$3.run(EventQueue.java:703) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80) 
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:726) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116) 
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) 
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93) 
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:82) 

我試過上面的代碼和路徑名/其他選項的許多變化,但每次得到的ClassNotFoundException。最初加載罐子時遇到問題,但使用固定的完全限定路徑,現在我無法加載類。

任何想法? :)

+0

你真的應該使用[的ServiceLoader(https://docs.oracle.com/javase/9​​/docs/api/java/util/ServiceLoader.html)爲了這。 – VGR

回答

0

再次看到我的問題,並意識到我忘了發佈一個解決方案,我發現我的問題。我希望這能幫助未來的人,因爲這是我發現的唯一一個我的情況 - 一個大學任務問題。我簡直不敢相信這是這個簡單:

byte[] classData = Files.readAllBytes(Paths.get(fileName)); 
Class<?> cls = defineClass(null, classData, 0, classData.length); 
return (PluginClassName)cls.newInstance(); 
1

這是URLClassLoader的一個功能,它與類的目錄一起工作(您可以假設爲.jar作爲打包目錄)。

constructor您使用具有以下的javadoc

構造,使用默認的委託父ClassLoader爲指定的URL構造一個新URLClassLoader。在首次在父類加載器中進行搜索之後,將按照爲類和資源指定的順序來搜索URL。任何以'/'結尾的URL都被假定爲指向一個目錄。否則,假定該URL是指將根據需要下載和打開的JAR文件。

如果你絕對要創建的類加載器爲每個單獨的類,你應該考慮繼承SecureClassLoaderdefineClass方法手動定義新類。

The basics of Java class loaders文章應該對你有幫助。

+0

感謝您的建議。由於實施時間和時間限制的困難,我決定避免允許.class文件。 –