3

現在、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 サーバーの経験はありません。そのため、Tomcat などの Java サーバーの構成が必要な場合は、それに関する情報が役立ちます。

どこから探し始めればよいのか、この問題に取り組むためのより良い方法があるのか​​どうかは本当にわかりません。そのため、あらゆる推奨事項や関連リンクを歓迎します。

4

2 に答える 2

2

ここでは、sinatra アプリをTomcatにデプロイする方法について説明します。

ロードした Java インスタンスへの参照を保持していれば、Java コードを一度ロードして再利用できます。ruby ではグローバル変数からの参照を保持できます。

注意すべきことの 1 つは、使用している Java ライブラリがスレッド セーフではない可能性があることです。Ruby コードを tomact で実行している場合、複数のリクエストを同時に実行でき、それらのリクエストはすべて共有 Java ライブラリにアクセスする可能性があります。ライブラリがスレッド セーフでない場合は、何らかの同期を使用して、複数のスレッドがライブラリにアクセスするのを防ぐ必要があります。

于 2013-04-27T14:14:28.323 に答える
2

はい、セットアップは可能です(展開については以下を参照)。それを達成するには、シングルトンを使用することをお勧めします

Jruby のシングルトン

質問を参照して:ラックにマウントされたアプリ/ミドルウェアのスタック間でオブジェクトを共有するための最良/最もエレガントな方法は? Colin Surprenantの答え、つまり、シングルトン mixin を使用するよりも好む singleton-as-module パターンに同意します

ここに、概念実証として使用できるテスト コードをいくつか投稿します。

JRuby シナトラ側:

#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

trinidadまたは単にtomcat で起動できますが、次の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 (誰がそんなことをするでしょうか?)、さらには Glassfish、Tomcat、JBoss などの Java 中心のアプリケーション コンテナーを使用してデプロイできます。ソース: jruby デプロイメント

JBoss Application Server 上に構築された TorqueBox を使用します。JBoss AS には、高性能のクラスタリング、キャッシング、およびメッセージング機能が含まれています。

trinidadは、組み込みの Apache Tomcat コンテナ内で任意の Rack ベースのアプレット ラップを実行できるようにする RubyGem です。

スレッド同期

Sinatra は Mutex#synchronize メソッドを使用してすべてのリクエストをロックし、スレッド間の競合状態を回避します。sinatra アプリがマルチスレッドでスレッド セーフでない場合、または使用する gem がスレッド セーフでない場合は、 set を実行し:lockて、true一度に 1 つのリクエストのみが処理されるようにする必要があります。.. それ以外の場合、デフォルトlockはです。これは、が直接ブロックに屈することfalseを意味します。synchronize

ソース: https://github.com/zhengjia/sinatra-explained/blob/master/app/tutorial_2/tutorial_2.md

于 2013-04-29T11:36:05.433 に答える