2012-12-13 132 views
5

我想創建一個可以動態加載插件的應用程序,但是我沒有在Internet上找到任何文獻。Java動態加載插件

困難的是:我不知道名字提前。

比如我有一個插件接口:

public interface Plugin { 
    public static Plugin newPlugin(); 
    public void executePlugin(String args[]); 
} 

這樣所有的類實現插件 jar文件列表中的實例:

Method method = classToLoad.getMethod ("newPlugin"); 
mylist.add(method.invoke(null); 
  1. 第一問題是,在接口中我不能有一個靜態方法。
  2. 第二個問題是,我不知道如何找到實現接口的

感謝您的幫助所有類。

+0

是否有配置文件指定哪些插件爲您的問題加載合適的解決方案? – Mac

+0

嗨,Mac在我的情況下,我想避免有一個配置文件,只是如果一個文件夾中存在一個jar試圖加載它。謝謝。 – FloFu

回答

20

因此,您似乎想要動態發現在運行時實現特定接口的類(例如,Plugin)。您有這兩種基本的選擇:

  1. 使用像OSGi的組件架構
  2. 使用Java的內部發現過程(ServiceLoader

既然有OSGi的很多很好的教程(也小的) ,我不會在這裏詳細說明。使用Java內部的發現過程,你需要做到以下幾點:

  • 捆綁所有你想要的「新」類發現到一個JAR文件
  • 創建一個新的文件 jar文件:META-INF/services/package.Plugin您必須使用此
  • 全包限制這個文件是一個簡單的文本文件,包含每類在JAR文件執行Plugin
  • 將是jar文件到您的類路徑(可能已經運行的全名)應用程序
  • 發現服務:

服務發現像這樣做:

ServiceLoader<Plugin> loader = ServiceLoader.load(Plugin.class) 
for (Plugin p : loader) { 
    // do something with the plugin 
} 

這裏有更多的細節:http://docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html

至於在接口的靜態方法:不可能的。它的語義也會有點奇怪,因爲靜態方法可以在沒有類的實例的情況下訪問,並且接口只是定義方法,而沒有任何功能。因此,靜態允許調用Interface.doSomething()而接口沒有定義任何功能,這隻會導致混淆。

編輯:

添加描述應該是在元文件

+0

我不認爲有人對你表示歡迎SirRichie,但你非常歡迎這個社區。投了所有四個答案:) –

+0

謝謝:)現在我只需要學習如何正確地格式化代碼... – SirRichie

+0

通常,您只需在第一行用4個空格縮進,然後跳過一行。然後,在另一空行之後,從0位置開始,爲其餘的普通文本開始。您可以使用內嵌代碼的字符環繞代碼。 –

2

關於你的第一個問題,不能夠有在接口的靜態方法是什麼,我的建議是簡單地使用接口有一個標記並實例化它。

你的插件接口可以簡單地是:

public interface Plugin { 
    public void executePlugin(String args[]); 
} 

然後你就可以這樣做:

if (someClass instanceOf Plugin) { 
    mylist.add(someClass.newInstance()); 
} 

這導致了第二個問題,你將如何得到someClass參考。 沒有標準的方式找到你的classpath實現一個給定接口所有類,雖然,你可以做一個方法是掃描的罐子在classpath中,如果給定的文件,.class結束確定它的全限定名通過它是jar中的路徑,並使用Class.forName()方法來實現Class。

在僞代碼是這樣的:

for each jar in your classpath { 
    for each file in JarFile { 
    if (file ends with .class) { 
     materialize class using Class.forName 
    } 
    } 
} 

隨着Class來說,如果它的實現你的Plugin界面,您可以檢查。

另外請記住,如果你需要添加任何上下文到你的插件,你可以在每個接收你的上下文對象的插件創建一個構造函數,而不是默認的構造函數。在這種情況下,而不是使用newInstance()你將不得不通過反射得到你想要的構造函數。