web-dev-qa-db-ja.com

ActiveMQと組み込みブローカー

編集:質問を言い換えました:

サーバーとクライアントアプリケーション間のメッセンジャーサービスとしてActiveMQを使用したいと思います。

クライアントが消費するために生成されたメッセージを処理するために、サーバー内に組み込みブローカー(つまり、別個のプロセスではない)をセットアップしようとしています。このキューは永続化されます。

ブローカーの初期化は次のとおりです。

BrokerService broker = new BrokerService();
KahaPersistenceAdapter adaptor = new KahaPersistenceAdapter();
adaptor.setDirectory(new File("activemq"));
broker.setPersistenceAdapter(adaptor);
broker.setUseJmx(true);
broker.addConnector("tcp://localhost:61616");
broker.start();

いじくり回した後、サーバーの部分は次のようになりました。

public static class HelloWorldProducer implements Runnable {
    public void run() {
        try {
            ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost"); // apparently the vm part is all i need
            Connection connection = connectionFactory.createConnection(); 
            connection.start();
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            Destination destination = session.createQueue("TEST.FOO");
            MessageProducer producer = session.createProducer(destination);
            producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            String text = "Hello world! From: " + Thread.currentThread().getName() + " : " + this.hashCode();
            TextMessage message = session.createTextMessage(text);
            System.out.println("Sent message: "+ message.hashCode() + " : " + Thread.currentThread().getName());
            producer.send(message);
            session.close();
            connection.close();
        }
        catch (Exception e) {
            System.out.println("Caught: " + e);
            e.printStackTrace();
        }
    }
}

クライアントは非常に似ており、次のようになります。

public static class HelloWorldConsumer implements Runnable, ExceptionListener {
    public void run() {
        try {
          ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost");
            Connection connection = connectionFactory.createConnection(); // exception happens here...
            connection.start();
            connection.setExceptionListener(this);
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            Destination destination = session.createQueue("TEST.FOO");
            MessageConsumer consumer = session.createConsumer(destination);
            Message message = consumer.receive(1000);
            if (message instanceof TextMessage) {
                TextMessage textMessage = (TextMessage) message;
                String text = textMessage.getText();
                System.out.println("*****Received: " + text);
            } else {
                System.out.println("*****Received obj: " + message);
            }
            consumer.close();
            session.close();
            connection.close();
        } catch (Exception e) {
            System.out.println("Caught: " + e);
            e.printStackTrace();
        }
    }

Mainメソッドは、これらのそれぞれをスレッドで開始して、メッセージの生成/受信を開始します。

...しかし、私は各スレッドの開始時に次のことに遭遇しています:

2013-01-24 07:54:31,271 INFO  [org.Apache.activemq.broker.BrokerService] Using Persistence Adapter: AMQPersistenceAdapter(activemq-data/localhost)
2013-01-24 07:54:31,281 INFO  [org.Apache.activemq.store.amq.AMQPersistenceAdapter] AMQStore starting using directory: activemq-data/localhost
2013-01-24 07:54:31,302 INFO  [org.Apache.activemq.kaha.impl.KahaStore] Kaha Store using data directory activemq-data/localhost/kr-store/state
2013-01-24 07:54:31,339 INFO  [org.Apache.activemq.store.amq.AMQPersistenceAdapter] Active data files: []
2013-01-24 07:54:31,445 DEBUG [org.Apache.activemq.broker.jmx.ManagementContext] Probably not using JRE 1.4: mx4j.tools.naming.NamingService
2013-01-24 07:54:31,450 DEBUG [org.Apache.activemq.broker.jmx.ManagementContext] Failed to create local registry
    Java.rmi.server.ExportException: internal error: ObjID already in use
    at Sun.rmi.transport.ObjectTable.putTarget(ObjectTable.Java:186)
    at Sun.rmi.transport.Transport.exportObject(Transport.Java:92)
    at Sun.rmi.transport.tcp.TCPTransport.exportObject(TCPTransport.Java:247)
    at Sun.rmi.transport.tcp.TCPEndpoint.exportObject(TCPEndpoint.Java:411)
    at Sun.rmi.transport.LiveRef.exportObject(LiveRef.Java:147)
        <snip....>

メッセージは正常に生成および消費されているようです(以前に投稿した他の問題は解決されました)が、上記の例外は私を心配しています。

編集:ブローカーのシャットダウン中に、私は今も次のように迎えられます:

2013-01-25 08:40:17,486 DEBUG [org.Apache.activemq.transport.failover.FailoverTransport] Transport failed with the following exception:
    Java.io.EOFException
    at Java.io.DataInputStream.readInt(DataInputStream.Java:392)
    at org.Apache.activemq.openwire.OpenWireFormat.unmarshal(OpenWireFormat.Java:269)
    at org.Apache.activemq.transport.tcp.TcpTransport.readCommand(TcpTransport.Java:210)
    at org.Apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.Java:202)
    at org.Apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.Java:185)
    at Java.lang.Thread.run(Thread.Java:722)
9

ブローカーはさまざまな方法でコードに埋め込むことができますが、その多くは文書化されています ここ 。使用しているものは、新しいKahaDBストアではなく現在非推奨のAMQストアにデフォルト設定されているため、かなり古いように見えるため、バージョンをアップグレードしてみることをお勧めします。 VMブローカーで作成するために競合する可能性のあるさまざまな接続ファクトリを使用するため、クライアントスレッド間の競合が原因で問題が発生している可能性があります。プロデューサーでcreate = falseオプションを設定した場合問題に対処できる後でコンシューマスレッドが開始することを確認するか、事前にVMブローカーを作成し、両方のスレッドにcreate = falseを追加すると、うまくいく可能性があります。

BrokerService broker = new BrokerService();
// configure the broker
broker.setBrokerName("localhost");
broker.setUseJmx(false);
broker.start();

そして、クライアントコードでは、この接続ファクトリ構成を介してアタッチするだけです。

ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost?create=false");
12
Tim Bish

コードを実行すると、次の例外が発生しました。

javax.jms.JMSException: Could not connect to broker URL: tcp://localhost. 
Reason Java.lang.IllegalArgumentException: port out of range:-1

ブローカーは実行されており、ポート61616をリッスンしているため、ブローカーに接続しようとするクライアントは、URLにポートを含める必要があります。

クライアントコードはローカルホストに接続しようとしますが、接続する必要のあるポートについては言及していません。プロデューサーコードとコンシューマーコードの両方を修正する必要があります。

ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost");

ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");

ポートを修正した後、私はあなたのコードを実行することができました。

4
Satish