2014-12-06 44 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)时,您可以重新加载服务。请注意,如果服务界面发生变化,您需要重新启动。但是,不改变服务接口的服务实现的任何更改都可以实时重新加载。