2014-06-25 82 views
0

我有一個大型的數據集。我正在創建一個允許用戶提交java源文件的系統,然後將其應用於數據集。更具體地說,每個提交的java源文件都必須包含一個具有特定名稱的靜態方法,比如說toBeInvoked()。 toBeInvoked會將數據集的一行作爲數組參數。我想調用數據集中每行提交的每個源文件的toBeInvoked方法。我也需要實現安全措施(所以toBeInvoked()不能做I/O,不能調用exit等)。在用戶提交的代碼中調用靜態方法的更好方法是什麼?

目前,我的實現是這樣的:我有一個java源文件的名稱列表。對於每個文件,我創建了我編碼的自定義安全ClassLoader的實例,該實例編譯源文件並返回編譯後的類。我使用反射來提取靜態方法toBeInvoked()(例如method = c.getMethod(「toBeInvoked」,double []。class))。然後,我遍歷數據集的行,並調用每行的方法。

至少有兩個問題我的做法:

  • 這似乎是痛苦的緩慢(我聽說反射趨於緩慢)
  • 代碼是比較複雜的,比我想

有沒有更好的方法來完成我想要做的事情?

+0

這裏的昂貴的東西很可能不是反射調用(除非它經常被稱爲*非常*),但彙編!你怎麼編譯這個?使用內置的'JavaCompiler'類,或通過外部的'Runtime.exec'調用?'在任何情況下,除了編譯之外,「插件」的功能通常可以通過http:// docs .oracle.com/javase/8/docs/api/java/util/ServiceLoader.html,儘管目前還不完全清楚這是否適用於您的情況。 – Marco13

回答

0

鑑於您自己設定的約束條件,沒有明顯更好的方法。

對於什麼是值得的,是什麼讓這個「痛苦緩慢」是編譯源文件到類文件並加載它們。這比使用反射來調用方法要慢許多個數量級。

(一個通用的接口,而不是靜態方法的使用不會使一個可測量的差異,以速度和複雜度的降低也比較小。)

如果你真的想簡化這一點,並加快步伐,請更改您的體系結構,以便將代碼作爲包含所有編譯類的JAR文件提供。

0

假設你#toBeInvoked()可以在一個界面來定義,而不是靜態的(應該是!),你可以只加載類,並把它轉換到接口:

Class<? extends YourInterface> c = Class.forName("name", true, classLoader).asSubclass(YourInterface.class); 
YourInterface i = c.newInstance(); 

然後調用# toBeInvoked()直接。

還可以查看java.util.ServiceLoader,如果您有多個源文件,可能會有助於查找加載的類。

0

就我個人而言,我會使用一個接口。這將允許您擁有多個具有自己狀態的實例(對多線程有用),但更重要的是,您可以使用一個接口,首先定義必須實現哪些方法,還可以調用方法。

反射很慢,但這只是相對於其他選項(如直接方法調用)。如果您正在掃描大型數據集,則必須從主內存中提取數據的事實可能會更加昂貴。

0

我會爲您的問題提出以下步驟。

  1. 要檢查方法是否包含任何不需要的代碼,您需要有一個檢查腳本,可以在上傳時檢查這些檢查。
  2. 創建一個具有方法toBeInvoked()(不是靜態方法)的接口。
  3. 上傳的所有類必須實現此接口並在此方法內添加邏輯。
  4. 你可以讓你的自定義類加載器掃描一個特定的文件夾來添加新的類並相應地加載它們。
  5. 上傳併成功驗證文件後,您可以編譯類文件並將其複製到類加載程序掃描的文件夾中。
  6. 您的處理器類可以查找新文件,然後在需要時在加載的類上調用toBeInvoked()方法。

希望得到這個幫助。 (請注意,我已經使用類似的機制在開發的Workflow Engine工具中動態加載工作流程步驟類)。

相關問題