我目前了解 Java 和 Ruby,但从未使用过 JRuby。我想在 Rack (sinatra) web 应用程序中使用一些 RAM 和计算密集型 Java 代码。特别是,这段 Java 代码将大约 200MB 的数据加载到 RAM 中,并提供了使用这些内存数据进行各种计算的方法。
我知道可以在 JRuby 中从 Ruby 调用 Java 代码,但在我的例子中还有一个额外的要求:该 Java 代码需要加载一次,保存在内存中,并作为共享资源供调用的 sinatra 代码(由多个 Web 请求触发)。
问题
- 这样的设置是否可行?
- 我需要做什么才能完成它?我什至不确定这本身是一个 JRuby 问题,还是需要在 Web 服务器中配置的问题。我有使用 Passenger 和 Unicorn/nginx 的经验,但没有使用 Java 服务器的经验,因此如果这确实涉及 Java 服务器(例如 Tomcat)的配置,那么任何相关信息都会有所帮助。
我真的不确定从哪里开始寻找,或者是否有更好的方法来解决这个问题,所以任何和所有建议或相关链接都非常感谢。
最佳答案
是的,一个设置是可行的(参见下面关于部署的内容),为了完成它,我建议使用 Singleton
Jruby 中的单例
引用问题:best/most elegant way to share objects between a stack of rack mounted apps/middlewares?我同意 Colin Surprenant的答案,即单例作为模块模式,我更喜欢使用单例混合
例子
我在这里发布了一些测试代码,您可以将其用作概念验证:
JRuby sinatra 方面:
#file: sample_app.rb
require 'sinatra/base'
require 'java' #https://github.com/jruby/jruby/wiki/CallingJavaFromJRuby
java_import org.rondadev.samples.StatefulCalculator #import you java class here
# singleton-as-module loaded once, kept in memory
module App
module Global extend self
def calc
@calc ||= StatefulCalculator.new
end
end
end
# you could call a method to load data in the statefull java object
App::Global.calc.turn_on
class Sample < Sinatra::Base
get '/' do
"Welcome, calculator register:#{App::Global.calc.display}"
end
get '/add_one' do
"added one to calculator register, new value:#{App::Global.calc.add(1)}"
end
end
您可以在 tomcat 中使用 trinidad
或简单地使用 rackup config.ru
启动它,但您需要:
#file: config.ru
root = File.dirname(__FILE__) # => "."
require File.join( root, 'sample_app' ) # => true
run Sample # ..in sample_app.rb ..class Sample < Sinatra::Base
关于 Java 方面的一些事情:
package org.rondadev.samples;
public class StatefulCalculator {
private StatelessCalculator calculator;
double register = 0;
public double add(double a) {
register = calculator.add(register, a);
return register;
}
public double display() {
return register;
}
public void clean() {
register = 0;
}
public void turnOff() {
calculator = null;
System.out.println("[StatefulCalculator] Good bye ! ");
}
public void turnOn() {
calculator = new StatelessCalculator();
System.out.println("[StatefulCalculator] Welcome !");
}
}
请注意,这里的register
只是一个double
,但在您的真实代码中,您可以在真实场景中拥有大数据结构
部署
您可以使用 Mongrel、Thin(实验性)、Webrick(但谁会这样做?),甚至以 Java 为中心的应用程序容器(如 Glassfish、Tomcat 或 JBoss)进行部署。 source: jruby deployments
使用基于 JBoss 应用服务器构建的 TorqueBox。 JBoss AS 包括高性能集群、缓存和消息传递功能。
trinidad是一个 RubyGem,允许您在嵌入式 Apache Tomcat 容器中运行任何基于 Rack 的小程序包装
线程同步
Sinatra 将使用 Mutex#synchronize 方法在每个请求上放置一个锁,以避免线程之间的竞争条件。如果你的 sinatra 应用程序是多线程的并且不是线程安全的,或者你使用的任何 gem 不是线程安全的,你会想要设置 :lock
, true
这样只有一个请求在给定时间处理。 .. 否则默认情况下 lock
为 false
,这意味着 synchronize
将直接让步给 block 。
来源:https://github.com/zhengjia/sinatra-explained/blob/master/app/tutorial_2/tutorial_2.md
关于java - JRuby:从 Rack 应用程序调用 Java 代码并将其保存在内存中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16201075/