RabbitMQ播放Java Akka

时间:2015-02-23 23:59:38

标签: java playframework rabbitmq akka

我正在使用Play Framework 2.2.2,我正在使用JavaAkka(Akka Actor System)实现RabbitMQ使用者应用程序。因此,当Play应用程序使用Global.OnStart函数启动时,我有一个MainActor。 MainActor创建RabbitMQ通道,然后从队列开始使用。该队列中的每条消息都是另一个队列的名称,该队列必须分配给另一个必须从消息中提到的队列开始消耗的子actor或子actor。基本上,我有一个订阅了一个RabbitMQ队列的MainActor和几个由Main actor创建的子actor,每个子actor都订阅了自己的RabbitMQ队列。问题是我出于某种原因无法培养超过7名儿童演员。我怀疑它是等待来自RabbitMQ的消息的子actor中的while(true)构造。这是我的实施:

主要演员:

import play.Logger;
import com.typesafe.config.ConfigFactory;

import java.io.IOException;

import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.ActorRef;

import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;
import play.libs.Akka;
import util.RabbitMQConnection;

public class MainActor extends UntypedActor {

@Override
public void onReceive(Object msg) throws Exception {

        try{
            Connection connection = RabbitMQConnection.getConnection();
            Channel channel = connection.createChannel();

            String main_queue_name = ConfigFactory.load().getString("rabbitmq.default_queue");

            channel.queueDeclare(main_queue_name, false, false, false, null);

            QueueingConsumer consumer = new QueueingConsumer(channel);
            channel.basicConsume(main_queue_name, true, consumer);

            while (true) {

                QueueingConsumer.Delivery delivery = consumer.nextDelivery();
                String message = new String(delivery.getBody());

                System.out.println(" [x] Received '" + message + "'");

                ActorRef childActor = getContext().actorOf(Props.create(childActor.class));
                childActor.tell(message, getSelf());
            }
        }catch (Exception e){
            System.out.println(e.toString());
        }
    }
}

儿童演员:

import play.Logger;
import com.typesafe.config.ConfigFactory;
import java.io.IOException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import play.libs.Akka;
import play.libs.Json;

import akka.actor.UntypedActor;

import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;
import util.RabbitMQConnection;


public class childActor extends UntypedActor {

@Override
public void onReceive(Object msg) throws Exception {

    ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
    String queue_name = ow.writeValueAsString(msg);

    try{
        Connection connection = RabbitMQConnection.getConnection();
        Channel channel = connection.createChannel();

        channel.queueDeclare(queue_name, false, false, false, null);

        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(queue_name, true, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());


            JsonNode jsonMsg = Json.parse(message);

            // Call some function to process the message

        }
    }catch (Exception e){
        System.out.println(e.toString());
    }
}
}

1 个答案:

答案 0 :(得分:1)

我认为在这种情况下你没有正确使用Actor。在我看来,对于给定的actor,你不应该在receive方法中有一段时间(真实)。另外,QueueingConsumer已被弃用,而且rabbitmq的人建议使用界面Consumer或默认的无操作实现DefaultConsumer来实现消费者。

我这样做的方式是:

  • 为rabbitmq实现一个自定义的使用者,每次获取某些东西时都会向该actor发送一条消息。
  • 对主要演员使用该实现。将队列名称作为消息发送,并以队列名称作为构造函数字段启动新的子actor。
  • 对子actor使用该实现。将收到的消息发送给actor并在actor本身中进行JSON解析。

这里的一些代码:( 警告:未编译或测试)

自定义rabbitmq消费者:

public class MyCustomRabbitMQConsumer extends DefaultConsumer {

    private ActorRef destinationActor;

    public MyCustomRabbitMQConsumer(ActorRef destinationActor) {
        this.destinationActor = destinationActor;
    }

    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) {
        destinationActor.tell(new String(body));
    }

}

主要演员:

import play.Logger;
import com.typesafe.config.ConfigFactory;

import java.io.IOException;

import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.ActorRef;

import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;
import play.libs.Akka;
import util.RabbitMQConnection;

public class MainActor extends UntypedActor {

    private MyCustomRabbitMQConsumer rabbitConsumer;

    @Override
    public void preStart() {
        Connection connection = RabbitMQConnection.getConnection();
        Channel channel = connection.createChannel();

        String main_queue_name = ConfigFactory.load().getString("rabbitmq.default_queue");
        channel.queueDeclare(main_queue_name, false, false, false, null);

        rabbitConsumer = new MyCustomRabbitMQConsumer(getSelf());
        channel.basicConsume(main_queue_name, true, rabbitConsumer);
    }

    @Override
    public void onReceive(Object msg) throws Exception {
        if(msg instanceOf String) {
            String queueName = (String) msg;
            System.out.println(" [x] Received '" + queueName + "'");
            getContext().actorOf(Props.create(childActor.class, queueName));
        }
    }
}

ChildActor:

import akka.actor.UntypedActor;

import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.QueueingConsumer;
import util.RabbitMQConnection;


public class ChildActor extends UntypedActor {

    private MyCustomRabbitMQConsumer rabbitConsumer;
    private String queueName;

    public ChildActor(String queueName) {
        this.queueName = queueName;
    }

    @Override
    public void preStart() {
        Connection connection = RabbitMQConnection.getConnection();
        Channel channel = connection.createChannel();

        String main_queue_name = ConfigFactory.load().getString("rabbitmq.default_queue");
        channel.queueDeclare(queueName, false, false, false, null);

        rabbitConsumer = new MyCustomRabbitMQConsumer(getSelf());
        channel.basicConsume(queueName, true, rabbitConsumer);
    }


    @Override
    public void onReceive(Object msg) throws Exception {

        if(msg instanceOf String) {
            String strMsg = (String) msg;
            JsonNode jsonMsg = Json.parse(message);

            // Call some function to process the message
        }
    }
}

这适用于n个演员。