2014-03-28 2 views
0

가 나는 JMS를 사용하여 MQ에 메시지를 전송하는 기능을 사용하여 웹 스피어 애플리케이션 서버에 배치 귀를 가지고 있고, 다른 큐 : 메시지를 보낸JMS 메시지를 MQ로 보내 완전히 커밋하는 방법은 무엇입니까?

ConnectionFactory cf = null; 
    InitialContext context = null; 
    String[] arrDatos_SR = null; 

    Connection conn = null; 
    Session session = null; 
    Queue queue = null; 
    Queue queue2 = null; 

    Destination dest = null; 
    Destination dest2 = null; 
    MessageConsumer consumer = null; 
    MessageProducer producer = null; 
    TextMessage message = null; 

    String comando = ""; 
    int tamanio = 0; 
    String tamanio2 = ""; 
    String cadena = ""; 

    try { 
     context = new InitialContext(); 
     cf = (ConnectionFactory) context.lookup(arrDatos[1].trim()); 
     conn = cf.createConnection(); 
     session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);  
     queue = (Queue) context.lookup(arrDatos[2].trim()); 
     queue2 = (Queue) context.lookup(arrDatos[3].trim()); 
     dest = (Destination) queue; 
     dest2 = (Destination) queue2; 

     producer = session.createProducer(dest); 


     // Create a text message using the queue session. 
     TextMessage textMessage = session.createTextMessage(); 

     textMessage.setText(arrDatos[4]); 

     textMessage.setJMSReplyTo(dest2); 
     textMessage.setJMSMessageID(arrDatos[6]); 
     textMessage.setJMSCorrelationID(arrDatos[7]); 
     producer.send(textMessage); 


    } catch (NamingException e) { 
     // TODO Auto-generated catch block 
     logger.error("MQSendReceive() - Exception e2 = " 
       + e, e); 
    } catch (JMSException e) { 
     // TODO Auto-generated catch block 
     logger.error("MQSendReceive() - Exception e2 = " 
       + e, e); 
    } 

     arrDatos[5] = arrDatos[5].trim(); 

     try{ 
      conn.start();  
      consumer = session.createConsumer(dest2); 
      Message receivedMessage = consumer.receive(Long.parseLong(arrDatos[5]) * 1000); 



      if(receivedMessage != null) 
      { 
       message = (TextMessage)receivedMessage; 
       comando = message.getText(); 
       comando = comando.trim(); 
       tamanio = comando.length(); 
       tamanio2 = StringUtils.leftPad(Integer.toString(tamanio), 9, '0'); 

       comando = StringUtils.rightPad(comando, Constantes.TAMANIO_RESPUESTA_DES_C1, ' '); 
       cadena = arrDatos[0] + comando + tamanio2; 
      } 
      else 
      { 
       comando = new String(); 
       comando = ""; 
       tamanio = comando.length(); 
       tamanio2 = StringUtils.leftPad(Integer.toString(tamanio), 9, '0'); 

       cadena = arrDatos[0] + comando + tamanio2; 
      } 

      arrDatos_SR = new String[2]; 
      arrDatos_SR[0] = cadena; 
      arrDatos_SR[1] = arrDatos[0]; 

     } 
     catch(Exception e) 
     { 
      logger.error("MQSendReceive() - Excepcion:" + e); 
     } 
     finally 
     { 
      try { 
       consumer.close(); 
       session.close(); 
       conn.close(); 
       context.close(); 
      } catch (JMSException e) { 
       // TODO Auto-generated catch block 
       logger.error("MQSendReceive() - Error desconectando de MQ - Excepcion:" + e); 
      } catch (NamingException e) { 
       // TODO Auto-generated catch block 
       logger.error("MQSendReceive() - Error desconectando de MQ - Excepcion:" + e); 
      } 

     } 

     return arrDatos_SR; 

에서 inmediately 메시지를 수신 aa MQ Queue # 1로 전송 된 다음 다른 MQ Queue # 2 로의 전송 큐인 다른 MQ Queue # 2로 전송됩니다. 필자는 Websphere MQ Administration GUI를 사용하여 메시지를이 대기열에 넣었으며 원활하게 전송합니다. 그러나 어떤 이유로 든 내 코드를 사용하면 전송이 즉시 이루어지지 않습니다. 대신 수신이 끝난 후 (수신 제한 시간이 만료되거나 실제로 메시지를받을 때) 수행됩니다.

누군가 이런 일이 일어나는 이유를 말해 줄 수 있습니까?

UPDATE : (3 월 31 일, 2014) 나는 @LocalBean, @Singleton 및 @TransactionManagement (TransactionManagementType.CONTAINER) 주석과 EJB 컨테이너를 사용하고 있음을 언급하는 것을 잊었다. SO (http://goo.gl/JBSW7r)에서이 게시물을 읽음으로써 전체 연결을 만드는 3 개의 클래스와 공용 메서드를 사용하는 객체로 모든 객체를 사용하는 하나의 기본 클래스가 있음을 알게되었습니다. 나는이 클래스들을 동일한 주석으로 EJB로 변환하기로 결정했다. 또한 각 메소드의 @TransactionAttribute 유형을 필수, 지원 및 필수 요소로 변경하려고 시도했지만, 일부는 작동하는지 테스트했습니다. 또한 세션 줄을 다음과 같이 변경했습니다.

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

결과가 동일하게 나타납니다. 메시지는 MessageConsumer의 시간 초과 간격 동안 메시지가 수신되는 동안 전송 큐에 여전히 고정되어 있습니다.

누군가 내게 이런 생각을 줄 수 있습니까?

답변

1

많은 노력 끝에 EJB 제거가 끝났습니다. 전체 로직으로 웹 프로젝트를 만들었습니다. while 루프를 사용하여 Thread를 사용하여 코드의 반복을 제어하기로 결정했습니다. 부울 변수를 사용하여 EAR 시작 및 종료시 while 루프의 초기화 및 중지를 제어합니다.

웹 응용 프로그램으로 돌아 가면 정상적으로 작동합니다. 나는 왜 그것이 다른 방식이 아닌이 방식으로 작동하는지 아직 모르지만, 지금은 괜찮다고 생각합니다.

2

문제점에 대한 귀하의 설명에 따라 귀하가 제공 한 코드가 컨테이너 관리 트랜잭션이 적용된 EJB의 컨텍스트에서 실행되고 있다고 생각됩니다. Java EE 응용 프로그램 서버에서 JMS 작업은 트랜잭션에 의해 조정됩니다. 이것은 트랜잭션이 EJB 메소드의 끝에서 컨테이너에 의해 커밋 될 때까지 실제로 send가 완료되지 않음을 의미합니다.

Java EE 응용 프로그램 서버에서 세션을 만들 때 false로 설정했지만 무시되며 세션은 적용된 모든 글로벌 트랜잭션에 등록됩니다.

이 문제를 해결하려면 JMS 전송이 트랜잭션없이 실행되도록해야합니다. 이를 수행하려면 EJB 메소드가 NOT_SUPPORTED의 트랜잭션 유형으로 구성되어야합니다.

+0

예, 저는 이것을 언급하는 것을 거의 잊었습니다. 죄송합니다. 그것은 EJB 컨테이너입니다. LocalBean 설정을 가진 Singleton Session Bean입니다. 거래 유형을 지정하지 않았습니다. Transacted에 대한 true 옵션을 사용하여 세션을 테스트했을 때, 배포시 IllegalStateException : 글로벌 트랜잭션에서 허용되지 않는 메소드가 발생했기 때문에 작동하지 않았습니다. 나는 이것이 서버가 EJB 컨테이너를 통해 커밋을 관리하고 있기 때문이라고 생각한다. 옵션을 false로 남겨두면 괜찮습니까? – Xanathos

+0

나는 몇몇 포스트를 주변에 읽고 있었다. 먼저, EJB는 DataQueue와 MQ 큐를 연결하기 위해 또 다른 3 개의 클래스를 사용합니다. 이것들은 Session Beans가 아니기 때문에, 이것이 내가 읽었던 것에 대한 문제 (http://goo.gl/JBSW7r)가 될지도 모른다고 생각했습니다. 그래서 다른 세 개의 클래스를 Singleton Session Beans (첫 번째 세션 Beans)로 바꾸 었습니다. 나는 또한 메인 EJB에 TransactionManagement.CONTAINER와 TransactionManagementType을 추가했다. (메인에는 REQUIRED이고, 실제 연결을 만드는 클래스에는 지원되지 않는다.) 여전히 작동하지 않습니다. 내가 뭔가 잘못하고 있는거야? – Xanathos

0

OP가 자신의 로직을 웹 모듈로 옮겨서 해결 방법을 찾은 것처럼 보이지만, 다른 사람들이 EJB를 사용해야하는 경우를 대비하여 잠재적 인 옵션을 추가 할 것이라고 생각했습니다.

Alasdair의 대답은 EJB 유형 논리를 웹 응용 프로그램으로 다시 이동시키는 데 선호되는 방법입니다. 새로운 EJB 3.0 프로젝트를 생성하고 메시지를 보내고 Websphere MQ로부터의 응답을 기다리는 bean을 정의 할 때이 문제가 발생했습니다.우리는 처음에 트랜잭션 유형이 컨테이너 인 Session Bean을 실제로 정의했음을 발견했는데, 앞에서 언급 한 정확한 이유 때문에 실패합니다.

그러나 트랜잭션 유형을 으로 변경하면 Bean이 문제를 해결했습니다. 세션 빈이 여전히 일부 트랜잭션 속성을 유지할 수 있도록 허용했지만 JMS가 커밋 된 메시지를 보내도록했습니다.

관련 문제