2011-05-10 23 views
0

我正在使用Java Enterprise(3.1)和Glassfish。我有兩個通過JMS同步通信的獨立EAR。更具體地講:同步MDB通信,最大池大小問題

EAR1使用JMS消息告訴EAR2做什麼。 EAR1開始偵聽來自EAR2(QueueReceiver.receive)的答案。 EAR2接收到該消息並相應地執行一些處理,然後將JMS消息發送迴帶有輸出的EAR1。

這一切工作正常。直到我得到這個例外:

[#|2011-05-10T15:05:27.382+0200|WARNING|glassfish3.1|javax.enterprise.resource.resourceadapter.com.sun.enterprise.connectors|_ThreadID=90;_ThreadName=Thread-1;|RAR5117 : Failed to obtain/create connection from connection pool [ jms/QueueConnectionFactory ]. Reason : com.sun.appserv.connectors.internal.api.PoolingException: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.|#] 

所以它看起來像容器沒有重用MDBs。相反,它創造了新的,直到我達到極限。我知道這是因爲EAR2中的MDB使用JMS發回結果。我的猜測是,仍然有一些資源在MDB實例中分配,導致行爲。

如果我只是用多邊開發銀行打印出接收到的消息,我可以繼續發送郵件整天,所以它肯定與JMS連接。

我一直在這兩天了,所以如果有人關心,提供一些幫助,這將不勝感激。

此代碼的工作一天到晚:

​​

雖然這一個犯規:

package xxx; 

import javax.ejb.ActivationConfigProperty; 
import javax.ejb.MessageDriven; 
import javax.jms.JMSException; 
import javax.jms.MapMessage; 
import javax.jms.Message; 
import javax.jms.MessageListener; 

@MessageDriven(activationConfig = { 
    @ActivationConfigProperty(
     propertyName="destinationType", 
     propertyValue="javax.jms.Queue") 
}, mappedName = "AssociationQueue1") 
public class AssociationMDB implements MessageListener { 

    @Override 
    public void onMessage(Message arg0) { 
     Logger logger = Logger.getLogger(this.getClass().getSimpleName()); 
     QueueConnection qConnect = null; 
     QueueSession qSession = null; 
     QueueSender qSender = null; 
     try { 
      InitialContext context = new InitialContext(); 
      Queue responseQ = (Queue)context.lookup("AssociationQueue2"); 
      QueueConnectionFactory factory = (QueueConnectionFactory) context.lookup("jms/QueueConnectionFactory"); 
      qConnect = factory.createQueueConnection(); 
      qSession = qConnect.createQueueSession(false,Session.AUTO_ACKNOWLEDGE); 
      qConnect.start(); 
      qSender = qSession.createSender(responseQ); 

      TextMessage answer = qSession.createTextMessage(); 
      answer.setText("hey"); 
      qSender.send(answer); 
      logger.info("message sent"); 
     } 
     catch (JMSException jmse) { 
      jmse.printStackTrace(); 
     } catch (NamingException e) { 
      e.printStackTrace(); 
     } 
     finally { 
      try { 
       if(qSender != null) { 
        qSender.close(); 
        logger.info("cleaning qSender"); 
       } 
       if(qSession != null) { 
        qSession.close(); 
        logger.info("cleaning qSession"); 
       } 
       if(qConnect != null) { 
        qConnect.close(); 
        logger.info("cleaning qConnect"); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 

    } 

(我也使用更新更看中的EJB類的東西符號等,但沒有工作或者嘗試。 ..)

塞巴斯蒂安

+0

這很有趣。偶然,你是否在連接池的「泡泡」上?你分配了多少個連接?如果bean的數量顯着高於JDBC池,我們也會遇到類似的問題。基本上,這項工作沒有做的太快,以至於連接被及時釋放,以便其他MDB獲得他們的交易。我懷疑你有同樣的問題。因此,無論是加快處理時間,增加超時時間,還是使池變大。 – Preston 2011-05-10 20:19:44

+0

我在想和你一樣,但是我已經設法將問題縮小到同步接收器。如果我用MDB替換同步接收器,我不再有問題。任何雖然如何解決這個問題?我仍然想使用同步調用。 – Sebastian 2011-05-12 08:59:06

+0

你可以展示你現在的兩種變化嗎? – Preston 2011-05-12 14:23:46

回答

2

模式本身似乎不是問題ATIC。 MDB肯定允許將消息發佈到另一個隊列。無論這是迴應某件事情還是代表工作,都與手頭的問題無關。

什麼似乎是一個問題是,你叫qConnect.start()。這爲準備連接以監聽入站流量。因此發送消息這是沒有必要的。您也不必明確關閉會話和發件人。儘管你在finally塊中關閉了連接,但是如果任何上面的代碼拋出,它很容易發生連接泄漏。

你的「不重用多邊開發銀行」措辭BTW也並不完全正確。我認爲你的意思是「不重用連接」?

它似乎也在同一個Glassfish實例上運行兩個EAR。這意味着EAR1使用與EAR2相同的連接池,因此連接泄漏也可能由調用QueueReceiver.receive的代碼引起。

最後請注意,直接聽入站流量JMS連接實際上是根本不允許在Java EE中,尤其是EJB的*。這是JMS API在Java EE產品中獨立運行並且使用不同的令人惱火的部分之一。有些服務器(例如JBoss AS)有不同的連接工廠,有些服務器可以用於監聽,有些則不可以。我不知道Glassfish的具體細節,但是您開始靜默聆聽的連接違反了規範,可能是您問題的主要根源。

*) 還有一些不重要的地方,它只關注EJB還是Servlets。例如。 JBoss AS 6禁止EJB和Servlet使用Java EE兼容的java:/ JmsXA監聽連接,但僅限Weblogic 8 EJB而不監聽Servlet。

0

Arjan給出了很好的解釋。感謝那。我只想添加一些東西。

在我的情況下,我通過使用@Resource而不是上下文查找來獲得連接工廠,我猜它非常非常相似。現在需要注意QueueConnection.close()由容器處理。因此,發起關閉並不一定意味着您的連接在此通話被觸發時關閉。在所有@Resource上記住這一點很重要。在創建MDB時,資源將通過DI進行初始化。在破壞MDB後,他們將再次獲得釋放。這是爲了提交和回滾的目的。

因此,如果您可能會從您的MDB會話中發送多條消息,則只有在您的MDB會話完成後纔會釋放這些連接。是的,我知道,通常是一個請求=一個響應,但在我的情況下,我得到一個CSV請求,以生成多個XML消息,並將每一行路由到一個隊列,如果你明白了。所以,一般來說,從你的sendMessage方法中調用ConnectionFactory.createQueueConnection,可能是一個冒險的想法。而是將QueueConnection實例作爲參數傳遞。