我怎样才能包括在交易中的JMS生产者当JMS PROD住在助手POJO类(How can I inc

2019-09-17 00:56发布

简短的问题:有没有办法强制通过一个无状态的EJB叫住在EJB的背景下,这样的交易和资源注入将在POJO工作POJO?

Specfically在我所试图做的背景:我怎么能包括在调用POJO之前坚持在数据库中的一些数据的EJB的交易一个POJO JMS生产者发送消息,使得如果该消息不能由于被发送到一个例外,该数据库事务将回滚呢? 我想异步发送邮件。

这是(无状态会话bean内开始)的快乐路径:

  • 数据保存到数据库//这工作
  • 从已持续数据拉选择数据,并将其放置在一个定制的“消息”类(一个真正的DTO)
  • 调用EmailQueueMessenger POJO的sendEmail方法传递给它的消息对象。
  • 消息被发送到MDB处理和发送电子邮件(对于完整性不是问题的一部分,只是在这里)

以下作品的代码,它只是不会回滚数据库“坚持”在调用的类,如果我强迫中说,上下文查找错误。 顺便说一句,我不能让@Resource注入要么工作。

//In the EJB
EmailQueueMessenger eqm = new EmailQueueMessenger();
eqm.sendEmail(messageObject);
// mailObject will be translated into an email message at the other end of the queue.  

/******************** POJO Below ************/  

public class EmailQueueMessenger implements Serializable {

    // Resource injection doesn't work... using 'lookup' below, which does work.
    //    @Resource(name = "jms/EmailerQueueConnectionFactory")
    //    private ConnectionFactory connectionFactory;
    //    @Resource(name = "jms/EmailerQueue")
    //    private Destination EmailerQueue;

        public EmailQueueMessenger() {
        }

        public void sendEmail(MailMessageDTO theMessage) {

            Context ctx = null;
            try {
                ctx = new InitialContext();
                ConnectionFactory connectionFactory = (ConnectionFactory) ctx.lookup("jms/EmailerQueueConnectionFactory");
                System.out.println("JMS Producer CTX Name In Namespace: " + ctx.getNameInNamespace());
                //Destination EmailerQueue = (Destination) ctx.lookup("jms/ERROR"); // forces exception
                Destination EmailerQueue = (Destination) ctx.lookup("jms/EmailerQueue");  // normal working code

                try {
                    Connection con = connectionFactory.createConnection();
                    Session session = con.createSession(false,
                            Session.AUTO_ACKNOWLEDGE);
                    MessageProducer msgProd = session.createProducer(EmailerQueue);

              ...

我曾尝试加入:

@TransactionAttribute(TransactionAttributeType.MANDATORY)
@Stateless

到POJO定义,但它不会有所作为。

FWIW我使用了EmailQueueMessenger单独的一类,因为会有,将需要发送的不定期电子邮件应用程序的其他部分,所以不想重复的代码。


应该指出,我做了一个测试,让我感动了所有JMS东西第一个EJB中,它正确地跑......但我需要这在一个单独的类的应用程序中的其他部分使用。

Answer 1:

我觉得你有2个问题:

  1. 你需要让你的POJO的SLSB。 应该注入到你的JMS侦听器,而不是直接调用,这样你正在处理的代理引用。 它仍然可以重新作为一个简单的POJO,因为如果在一个容器中没有部署注释将被忽略。

  2. 您正在使用AUTO_ACKNOWLEDGE创建JMS会话,但它需要办理。 另外,确保JMS连接从事务JCA源来,因为这将在会议上向交易相关联。

========= =========更新

嘿,比尔;

道歉,我以为外豆是JMS侦听出于某种原因.....不管怎么说,这个问题是一样的。

如果你想EmailQueueMessenger到按照您把注释行为(事务,注射等),你必须引用它作为一个EJB,而不是一个简单的POJO。 因此,你的外会话bean应该是这样的:

@EJB   // key difference
private EmailQueueMessenger eqm;

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void sendMessage(Object messageObject) {
   eqm.sendEmail(messageObject);
}

现在你

@Resource(name = "jms/EmailerQueueConnectionFactory")
@Resource(name = "jms/EmailerQueue")

@TransactionAttribute(TransactionAttributeType.MANDATORY)
@Stateless

注释将荣幸。

最后,你的JMS发送方将在调用点交易进行注册,您需要确保事务管理器知道你是在交易(第一DB,现在JMS)争取第二资源管理器。 我不是那个熟悉的GlassFish,但似乎有一个开关,允许您指定一个配置屏幕的事务支持的连接工厂的水平 。

我会改变发送者的代码:

Session session = con.createSession(true, Session.SESSION_TRANSACTED);

从技术上讲,你可以在EmailQueueMessenger实例缓存JMS连接实例。 您的代码不应该关闭JMS会话交易完成后将进行处理(虽然我已经看到了这一点JMS / JTA实现之间的差异)。

我希望清除它,我真的希望工程!



文章来源: How can I include a JMS Producer in a Transaction when the JMS Prod lives in a helper POJO class