java - JRuby:从 Rack 应用程序调用 Java 代码并将其保存在内存中

标签 java sinatra jruby rack

我目前了解 Java 和 Ruby,但从未使用过 JRuby。我想在 Rack (sinatra) web 应用程序中使用一些 RAM 和计算密集型 Java 代码。特别是,这段 Java 代码将大约 200MB 的数据加载到 RAM 中,并提供了使用这些内存数据进行各种计算的方法。

我知道可以在 JRuby 中从 Ruby 调用 Java 代码,但在我的例子中还有一个额外的要求:该 Java 代码需要加载一次,保存在内存中,并作为共享资源供调用的 sinatra 代码(由多个 Web 请求触发)。

问题

  1. 这样的设置是否可行?
  2. 我需要做什么才能完成它?我什至不确定这本身是一个 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 这样只有一个请求在给定时间处理。 .. 否则默认情况下 lockfalse,这意味着 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/

相关文章:

java - Cucumber 和/或 RSpec 与使用 JRuby 的纯 Java 应用程序

java - FitNesse 测试返回 "Class RunEtlFixture is not a fixture"

ruby - 在 Ruby (Sinatra) 中循环一年中的几周

ruby - Sinatra 和 Grape API 在一起?

sinatra - 为什么 BCrypt 在这种情况下无法进行身份验证?

ruby - Rubinius 和 JRuby 怎么可能这么慢?

java - 如何将变量从 try 传递到 action 事件?

java - 警报 JSP 后保持输入的详细信息不变

java - 用于接触 netbeans 的不同软件包

java - 将 jruby 脚本打包为带有注释的 .jar