Play Framework 2.5 在另一个线程中接收数据时没有 EntityManager 错误

No EntityManager Error in Play Framework 2.5 recieving data in another thread

使用 Java

的 play Framework 2.5

我想创建一个应用程序,它使用来自 ActiveMQ 的数据,并根据收到的这条消息对数据库执行一个休眠查询并存储一个对象用户。 我已经简化了我的消费者 class 以便在那里创建一个对象并同时调用持久性。

当我从接收测量值的线程(或调用另一个 class)调用持久性时,我的问题就来了。然后 EntityManager 在那里不存在,我无法创建一个新的,或者坦率地说,我不知道在 Play 中创建它。

package controllers;

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

import models.User;
import play.Logger;
import play.db.jpa.JPA;

public class MessageConsumerController implements Runnable, ExceptionListener {
    private static final String TOPIC_NAME = "miguelTopic";
    private static Thread consumerService;

    public static synchronized void initService() {
        Logger.info("Message Consumer initialized");
        MessageConsumerController MessageConsumer = new MessageConsumerController();
        if (consumerService != null) {
            Logger.info("STOPPING MessageConsumer thread.");
            consumerService.interrupt();
        }
        Logger.info("Starting MessageConsumer thread.");
        consumerService = new Thread(MessageConsumer);
        consumerService.setDaemon(true);
        consumerService.setName("MessageConsumer Service");
        consumerService.start();
        Logger.info("MessageConsumer thread started.");
    }

    @Override
    public void run() {
        try {

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

            Logger.info("Creating ActiveMQ connection");
            Connection connection = connectionFactory.createConnection();
            connection.start();
            connection.setExceptionListener(this);
            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

            Logger.info("Connecting to topic " + TOPIC_NAME);
            Destination destination = session.createTopic(TOPIC_NAME);

            Logger.info("Creating consumer");
            MessageConsumer consumer = session.createConsumer(destination);

            while (!Thread.currentThread().isInterrupted()) {
                Logger.info("Wait for messages...");
                Message message = consumer.receive();

                if (message instanceof TextMessage) {
                    TextMessage textMessage = (TextMessage) message;
                    String text = textMessage.getText();
                    Logger.info("Received: " + text);
                    User user = new User();
                    user.setId(555);
                    user.setName("miguel");
                    user.setTime_of_start("time");
                    Logger.info("insert user");

                    //JPAApi jpa = Play.current().injector().instanceOf(JPAApi.class);

                    JPA.em().getTransaction().begin();
                    JPA.em().persist(user); // 
                    JPA.em().getTransaction().commit();



                } else {
                    Logger.info("Received: " + message.getClass().getSimpleName());
                }

            }
            Logger.info("Message consumer interrupted.");
            consumer.close();
            session.close();
            connection.close();
        } catch (Exception e) {
            if (e instanceof InterruptedException) {
                Logger.info("Message Consumer thread interrupted.");
            } else {
                Logger.error(e.getLocalizedMessage(), e);
            }
        }
    }

    public synchronized void onException(JMSException ex) {
        Logger.error("JMS Exception occured.  Shutting down client.");
        Logger.error("ErrorCode=" + ex.getErrorCode() + " , " + ex.getMessage(), ex);
    }

}

我曾尝试注入 JPaapi 以及更多不同的东西,但我几乎是 Play Framework 的新手

首先,在 Play Framework 中,我建议使用 Akka actor 而不是传统的 java 线程。一开始它可能看起来很复杂,但是一旦掌握了它,它将节省大量调试时间。 Akka 已经集成在 Play 中,所以应该不是问题。

现在,关于您的实体管理器。首先,确保你的 sbt 构建文件中有 java JDBC:libraryDependencies += javaJdbc

接下来,在您的配置文件中,确保您配置了默认 DS:db.default.jndiName=DefaultDS 以及一个持久性单元(更多信息:https://www.playframework.com/documentation/2.5.x/JavaJPA

现在,您的控制器(我在您发布的代码中没有看到实际控制器)必须具有 @Transactional 注释。