簡體   English   中英

從 Java 調用 Ruby 方法

[英]Calling Ruby method from Java

我有一個依賴於 ruby​​ 腳本結果的 Java 應用程序。 我面臨的問題是這個 ruby​​ 腳本被多次調用,每次執行時都需要加載腳本的庫。

我不熟悉 Ruby,但在我的搜索中我遇到了 JRuby。 由於它解釋 ruby​​ 代碼並在 JVM 上運行它,我最初的想法是“太好了,我可以將 ruby​​ 腳本編譯為 .class 文件並將其打包並像常規 java 對象一樣與之交互”。 這將避免每次執行 ruby​​ 腳本時加載庫所帶來的開銷。

在深入研究 jruby 之后,我明白它不是這樣工作的。 所以為了做我想做的事,我可以使用 JRuby 的 JavaEmbedUtils

  1. 用我的 ruby​​ 腳本加載一個 Ruby 運行時對象
  2. 創建一個接收器對象,它本質上知道如何處理和響應我的腳本。
  3. 從腳本調用所需的方法。

這就是我的想法(我很快就會測試)

// 1  
List<String> paths = new ArrayList<>();  
paths.add(".");  
Ruby runtime = JavaEmbedUtils.initialize(paths);

// 2  
String script = "/path/to/script.rb";  
IRubyObject recvr = JavaEmbedUtils.newRuntimeAdapter().eval(runtime, script);

// 3 Call this many times   
JavaEmbedUtils.invokeMethod(runtime, receiver, "method", null, null);

我的理解是否正確,因為這種方法允許我在加載腳本庫一次時多次使用腳本的內容? 有沒有替代的或更多的 JRuby 方式來做我正在尋找的事情?

更新

因此,我測試了類似於 Eugene 建議的內容 (a) 即 ScriptingContainer 並將其與使用 (b) java.lang.Runtime 調用腳本進行了比較,總共運行了 30 次。

  1. 平均而言,(a) 快了大約 8 倍 (b)
  2. 初始化 (a) 的運行時間大約需要 7 秒
  3. (a) 和 (b) 的初始運行時間比后續運行時間長 40 倍和 150-250 倍。
  4. (a) 的初始運行比 (b)s 快 11 倍

這就是我在 Java 代碼的腳本容器中使用 JRuby 的方式:

import org.jruby.*;
import org.jruby.embed.LocalVariableBehavior;
import org.jruby.embed.PathType;
import org.jruby.embed.ScriptingContainer;

ScriptingContainer container = new ScriptingContainer(LocalVariableBehavior.PERSISTENT);
container.setCompileMode(RubyInstanceConfig.CompileMode.OFF);
container.setNativeEnabled(false);
container.setObjectSpaceEnabled(true);
container.put("some_param", someValue);

// My script return an array - tweak to fit your returning value
RubyArray resourceArray = (RubyArray) container.runScriptlet(PathType.CLASSPATH, scriptPath);

我必須注意到 JRuby 在啟動時太慢(這些​​數字不太精確,但在我的情況下,即使在 4Ghz + SSD 上也是 2-3 秒)。 TDD 會因這種延遲而變得痛苦。 這就是為什么要對對象空間等進行一些調整的原因。

此外,我必須刪除這個模塊,以便其余的測試使用其他裝置並在不啟動 JRuby 的情況下運行。 換句話說,我不必在單獨運行另一個測試時啟動它。

聚苯乙烯

我的理解是否正確,因為這種方法要求我只加載一次腳本的依賴項?

我不確定你在這里是什么意思,但似乎每次使用這種方法時,JRuby 端“需要”的所有依賴項都會被加載。

無論如何,我之前會做一個基准測試。 也許不值得考慮。

更新:

這比我想象的要簡單:

常見的.rb:

puts "common"

腳本.rb:

require 'common'

puts "script"

代碼:

ScriptingContainer container = new ScriptingContainer(LocalVariableBehavior.PERSISTENT);
for (int i = 0; i < 3; i++) {
    container.runScriptlet(PathType.CLASSPATH, "script.rb");
}

輸出:

common
script
script
script

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM