2014-12-06 43 views
10

我正在開發一個基於組件的遊戲引擎,現在當我對組件進行更改時,我需要重新生成並重新啓動編輯器以使更改生效(或者我可以使用一些有限的熱門代碼如果應用程序在調試模式下運行,則進行注入)。如何集成beanshell

我正在尋找一種方法來允許用戶修改組件的來源並重新加載它們而不必重新啓動應用程序(也許只需退出並進入遊戲模式)。此外,我需要的一個重要功能是最終導出的代碼應該是原生Java代碼(因此在最終結果中不應該使用解釋器))。

你可以給我一些關於如何在項目中集成beanshell解釋器的指針嗎?我可以手動監視源文件夾中的更改並將更新的Java類提供給它,但熱交換將如何發生?

+0

http://www.beanshell.org/manual/embeddedmode.html – 2014-12-09 13:29:59

+0

我想知道沒有人提到OSGi。 http://en.wikipedia.org/wiki/OSGi – Yser 2014-12-15 13:19:48

回答

4

首先,標題有點混亂。您不需要集成BeanShell。你真正需要的是什麼:

  1. 定義一個適當的架構
  2. 使用Java編譯器API,以便與Java類的工作

架構

假設你有一個對象圖。有很多對象,引用等等。因此,用新的實例替換某個實例將是一件非常棘手的任務。您可以隱藏「靜態」代理後面的動態部分,而不是解決這個問題。代理將處理所有重新加載的東西(包括源文件夾監視)。

重裝前:

enter image description here

重裝後:

enter image description here

有了這樣做需要的時候,你可以很容易地跟蹤更改和更新動態部分。

Java編譯器API

而不是使用解釋性語言,你可以使用Java,編譯它使用的飛行和裝載 '的Class.forName()' 的。由於這種方法存在一段時間,因此有很多不同的例子。

這裏還有一些細節:

+0

我的問題非常具體,如何整合* beanshell *做熱插拔,沒有人回答。我不想手動重新編譯代碼並手動管理動態重新加載,也值得注意的是,動態部分和靜態部分之間的代理是不可行的,因爲它會在最終設備(包括一些舊設備j2me設備)。 – 2014-12-16 08:27:35

+0

你的答案看起來對於其他有類似問題的人來說是最完整的,所以我選擇它作爲賞金。 – 2014-12-16 08:29:00

0

基本上要實現extensibility或插件的設計模式。有多種方式來實現這種情況。

您希望哪個組件可以允許其他人重新加載模塊,定義一個接口並將您自己的實現作爲默認實現來實現。例如,在這裏,我想提供一個HelloInterface,每個國家都可以實現,隨時隨地加載,

public interface HelloInterface { 

    public String sayHello(String input); 
    .. 
} 

public class HelloImplDefault implements HelloInterface { 

    public String sayHello(String input) { 
     return "Hello World"; 
    } 
} 

現在允許用戶將文件添加一個插件(自定義實現),以預先配置的路徑。您可以使用FileSystemWatcher或後臺線程來掃描此路徑並嘗試編譯和加載文件。

編譯Java文件,

private void compile(List<File> files) throws IOException{ 


     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
     DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 
     StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); 
     Iterable<? extends JavaFileObject> compilationUnits = fileManager 
      .getJavaFileObjectsFromFiles(files); 
     JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, 
      null, compilationUnits); 
     boolean success = task.call(); 
     fileManager.close(); 

} 

裝入類文件,

private void load(List<File> files) throws MalformedURLException, InstantiationException, IllegalAccessException, ClassNotFoundException{ 

    ClassLoader cl = Thread.currentThread().getContextClassLoader(); 

    for(File f: files){ 
     if(f.getName().endsWith(".class") && !loadedClass.contains(f.getName())){ 
      URL url = f.toURL(); 
      URL[] urls = new URL[]{url}; 
      Object obj = cl.loadClass(f.getName().replace(".class", "")).newInstance(); 
      if(obj instanceof HelloInterface){ 
       HelloProviders.addProvider((HelloInterface)obj); 
       System.out.println("Loaded "+ ((HelloInterface)obj).getProviderName()); 
      }else{ 
       //Add more classes if you want 
      } 
      loadedClass.add(f.getName()); 
     } 
    } 
} 

在這一點上,你可以閱讀定製實現和系統類加載器加載。現在你已經準備好了。這種方法存在安全隱患,您需要從互聯網上學習。

我實現了一個示例代碼併發布在github上,please take a look。快樂的編碼!

0

看看tapestry-ioc控制容器的倒置,它支持live-reloading

當處於開發模式(tapestry.production-mode = false)時,您可以重新加載服務。請注意,如果服務界面發生變化,您需要重新啓動。但是,不改變服務接口的服務實現的任何更改都可以實時重新加載。