使用Groovy动态更改Java应用程序的行为

时间:2015-03-29 02:14:27

标签: java dynamic groovy

我正在研究动态修改Java应用程序行为的方法(具体来说,我正在尝试制作一个Minecraft mod,允许用户通过编写代码来修改他们找到的对象的行为,而无需重新启动游戏我偶然发现了Groovy。我的问题是:是否有可能以他们“共享”对象的方式集成Java和Groovy? (我正在考虑使用一组特定的实际Groovy代码类,以便您可以在运行时更改代码,类似于您在任何Smalltalk实现中可以执行的操作)

4 个答案:

答案 0 :(得分:4)

看看Integrating Groovy in a Java Application。它显示了如何使用groovy.lang.Binding从Java应用程序内部运行Groovy脚本并在它们之间共享数据的示例。

答案 1 :(得分:3)

多么酷的主意!

<强> 1。 Groovy: Java和Groovy可以共享对象并来回调用。实现Java接口的Groovy类很容易从Java调用。 (还有其他方法,比如从Java调用groovyObject.invokeMethod("methodName", args)。)对于JVM语言,Groovy与Java有最紧密的集成。 Java程序员也很容易学习,因为它与Java共享很多东西。

本书Groovy in Action有一章“集成Groovy”,解释和比较这些方法(比the reference docs更详细):GroovyShell,GroovyScriptEngine,GroovyClassLoader,Spring集成和JSR-223 ScriptEngineManager。 GroovyClassLoader是最有能力的选择。

然而,虽然很容易在运行时编译和加载Groovy代码,但我很困惑如何改变现有对象实例的行为(缺少下面关于热交换的注释< / em>的)。 (这可能取决于类是重写Java接口还是子类化Java类。)请考虑:

class G implements Runnable {
  void run() { println 'Groovy' }
}

g = new G()
g.run()

这会打印Groovy。现在重新定义班级:

class G implements Runnable {
  void run() { println 'Groovy!' }
}

g1 = new G()
g.run()
g1.run()

打印

Groovy
Groovy!

现在使用元类在运行时更改方法:

G.metaClass.run = { println 'Groovy!!!' }

g2 = new G()
g.run()
g1.run()
g2.run()

打印

Groovy
Groovy!
Groovy!

如果我们从这些类定义中省略implements Runnable,那么最后一步将打印

Groovy
Groovy!
Groovy!!!

但是我们的类确实实现了Runnable,现在执行:

G.metaClass.run = { println 'Very Groovy!!!' }

g3 = new G()
g.run()
g1.run()
g2.run()
g3.run()

打印:

 Groovy
 Groovy!
 Very Groovy!!!
 Very Groovy!!!

解决方法是在类变量中保存的闭包中实现方法。

<强> 2。热交换:如果要点是在运行时为具有现有实例的类重新定义方法体,那么您只需在IDE的调试器中运行并使用热交换

E.g。对于IntelliJ,这里是Java和Groovy代码的instructions to configure hot swapping

第3。扩展热插拔:如果您还希望能够在运行时添加/删除方法和实例变量,请通过DCEVM(JetBrains article on extended hot swapping)查看此Dynamic Code Evolution VM

请参阅https://github.com/HotswapProjects

上的热插拔代码

另见SO Q&A on hot swapping techniques

答案 2 :(得分:1)

我不确定使用Groovy可以在不编译的情况下完成的事情。你可以做到,但是#34;脚本&#34; Groovy的方面不会帮助你。我希望让玩家编写javascript并使用Java ScriptEngine。见这里:http://docs.oracle.com/javase/7/docs/technotes/guides/scripting/programmer_guide/

答案 3 :(得分:1)

是的,你可以做到这一点。例如,你有一些用java编写的东西,它使用一些来自let spring的对象。所以现在你能做的是:

  • 在执行java代码之前执行groovy脚本,
  • 使用委托设计模式来包装它,覆盖一些方法
  • 最终将其重新置于上下文中。

基本上,在执行Java代码的那一刻,他将获得一个包装对象,并在运行时进行一些更改。

如果您正在尝试做什么,请告诉我,我可以为您编写一些示例代码。