2012-04-03 91 views
26

我正在開發一個應用程序(Quartz scheduler),我們有一個工作類負責實際執行工作,我們需要告知/傳遞作業類的名稱同時在Quartz調度器中創建一個觸發器。查找所有實現特定接口的類

我想爲所有想使用API​​的人提供一個擴展點(除了我將作爲API的一部分提供的一些通用作業之外)。這個想法是創建一個(標記)接口,如果任何人想將他們的類聲明爲調度器作業類,他們所要做的就是(聲明)實現接口。

我不知道如何找到哪些類遵循合同(通過實現接口),以便我可以將它們展示給希望在調度程序中調度觸發器的用戶。

我的要求是不在運行時加載類,而是顯示實現所需接口的類的用戶列表,以便用戶可以選擇類並將類名傳遞給調度程序。這是Quartz調度器,最後將負責創建一個類的實例。

任何人都可以建議我如何實現上述目標,或者是否有其他更好的方法來實現我想要做的事情?

編輯

我通過ServiceLoader的文檔去了,似乎是實現服務一個具有創建在META-INF文件夾中的文件,實現類的名字,這使我認爲如果我的API的用戶需要20個不同的實現,他必須在文件中放入20個條目,這對我來說似乎對最終用戶來說是很多額外的工作,因爲每個工作類將被創建用於執行特定工作,並且可以成爲100個工作班。

如果我的假設錯誤,請糾正我。

+2

另一個嘗試是創建一個註釋,然後搜索註釋的類。這裏http://stackoverflow.com/questions/259140/scanning-java-annotations-at-runtime說如何實現它。 – polypiel 2012-04-03 10:21:43

+0

這會有幫助嗎? [鏈接](http://www.javaworld.com/javaworld/javaqa/2003-07/02-qa-0725-classsrc2.html?page=1) – titogeo 2012-04-12 09:20:04

回答

30

我也有類似的需要,我想請確保實現某個接口創建的任何類總是真正的序列化。我創建了一個JavaClassFinder,它遍歷類路徑中的所有目錄,並查找可分配給我關心的接口的所有類。這裏是一個代碼片段:

public <T> List<Class<? extends T>> findAllMatchingTypes(Class<T> toFind) { 
    foundClasses = new ArrayList<Class<?>>(); 
    List<Class<? extends T>> returnedClasses = new ArrayList<Class<? extends T>>(); 
    this.toFind = toFind; 
    walkClassPath(); 
    for (Class<?> clazz : foundClasses) { 
     returnedClasses.add((Class<? extends T>) clazz); 
    } 
    return returnedClasses; 
} 

我很高興與您分享代碼,如果它有幫助。唯一的缺點是,這隻能處理.class文件 - 我沒有添加該功能來解壓縮.jars並從那裏讀取類文件。 (但它不會是一個巨大的項目添加)。

更新:我檢查了我的上述源代碼,發現它取決於我們的標準實用程序庫中的很多幫助類。爲了更容易,我將所有需要的代碼壓縮,你可以從JavaClassFinder.zip下載。這將直接在Eclipse中設置,並且您可以獲取所需代碼的任何部分。

您將在項目中找到名爲JavaClassFinderTest.java的JUnit3測試,該測試向您展示了JavaClassFinder類的功能和用法。運行Junit測試所需的唯一外部依賴是Junit。

該實用程序的基本用法:

JavaClassFinder classFinder = new JavaClassFinder(); 
    List<Class<? extends MyTagInterface>> classes = classFinder.findAllMatchingTypes(MyTagInterface.class); 

這會給你包含在classpath這是從「MyTagInterface.class」(例如)分配的任何類的列表。希望這可以幫助。

+0

缺乏「walkClassPath」方法。你可以提供嗎? – 2012-04-11 12:45:16

+0

@YvesMartin:Yves,我更新了我的答案,包括所有鏈接以下載原始代碼。它可能比你想要的要多,但它是一個完整的工作版本。 – 2012-04-11 15:32:34

+2

@SamGoldberg你在這裏設計的優秀實用工具。 – shashankaholic 2012-04-12 09:33:55

0

可能是使用Java SPI機制完成此操作的最佳(標準)方法,請參閱Javadoc。不方便(這也是一個不錯的功能)是,它期望Jars定義擴展名以在META-INF/services/your.fully.qualified.Interface中列出它們。

我能想到的唯一方法就是穿過所有ClassLoaders,希望你能夠列出那裏的文件,加載類文件,看看它們是否實現了你的接口 - 這是這不是一件好事。

27

您可以在這裏找到答案here

我可以建議使用org.reflections

enter link description here

Reflections reflections = new Reflections("com.mycompany");  
Set<Class<? extends MyInterface>> classes = reflections.getSubTypesOf(MyInterface.class); 
+0

感謝您的輸入,我正在通過ServiceLocator文件,它似乎對於我的接口(服務)的每個實現,最終用戶必須將該條目放在文件中才能加載,這就好像開發人員希望他/她需要20個這樣的實現來將所有這些實用名稱放在文件,對於最終用戶來說似乎很多工作。 – 2012-04-03 11:43:50

1

我認爲org.reflections是由亞歷克斯Stybaev提到一個妥善的解決辦法,你並不需要引用在屬性文件中的類。

另一種方法(我會採取)是Spring,因爲我對我的應用程序使用Spring,因此不需要任何額外的依賴項。

你可以在這裏找到(在其他意見或答案,備選方案),與春天解決您的問題提示:

在評論你的問題heikkim和polypiel也鏈接到有問題的答案用Spring解決它:

0

要在純java做到這一點,最正確的答案是已經投(薩姆·戈德堡四月10,2012)

他是過於複雜,但是完整的代碼。我使用他的想法,並推動了ClassFinder: http://icedtea.classpath.org/hg/icedtea-web/file/0527ad4eb2dd/netx/net/sourceforge/jnlp/controlpanel/ClassFinder.java

注意 - 這將在獨立的應用程序(或任何使用普通類路徑與罐和dirs)不在ServerContainer中工作。

如果您的應用程序在網絡服務器上運行,您需要知道您的戰爭/耳朵的位置並在那裏搜索。或者你必須問你的父母classlaoder他在哪裏得到你的(和其他)來源。

第二個注意事項 - 我正在過濾最終位置類,只匹配netx和icedtea-web,因爲我不會搜索依賴關係。所以如果你需要包含rt.jar,請使用這些過濾器。或者,如果你相反根本不需要bootclasspath的話。

相關問題