用于测试 IBM-MQ 的服务器和客户端应用程序中的问题

Problem in server and client application for testing IBM-MQ

我有两个用于测试 MQ 事件的应用程序。其中一个用于发送消息,另一个用于接收消息。它们都是 SpringBoot 应用程序。 发件人应用 运行ning port: 8000 接收方应用 运行ning port: 8050
pom.xml

    <dependency>
        <groupId>com.ibm.mq</groupId>
        <artifactId>mq-jms-spring-boot-starter</artifactId>
        <version>2.5.0</version>
    </dependency>

这是发件人应用程序。

@SpringBootApplication
@EnableJms
@RestController
public class MqTestApplication {

    private static final String ISSUER = "254874125487";
    private static final String ACCOUNT_NO = "1234567890123";

    @Autowired
    private JmsTemplate jmsTemplate;

    public static void main(String[] args) {
        SpringApplication.run(MqTestApplication.class, args);
    }

    public Event getEvent() {
        Event event = new Event();
        Map<String, Object> argument = new HashMap<>();
        argument.put("key-accNo", ACCOUNT_NO);
        event.setMessageId(String.valueOf(UUID.randomUUID()));
        event.setIssuer(ISSUER);
        event.setType(EventType.ACCOUNT);
        event.setName(EventName.OPEN_ACCOUNT);
        event.setArgument(argument);
        event.setDateTime(LocalDateTime.now());
        return event;
    }

    @GetMapping("send/event")
    public void sendEvent() {
        try {
            jmsTemplate.convertAndSend("DESTINATION", getEvent());
        } catch (JmsException ex) {
            ex.printStackTrace();
        }
    }
}

接收方应用程序

@SpringBootApplication
@EnableSwagger2
@EnableJms
public class Application {

public static void main(String[] args) {
       SpringApplication.run(Application.class, args);
}

}
@Service
public class MQServiceImpl{

    private final JmsTemplate jmsTemplate;
    
    @Autowired
    public MQServiceImpl(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }

    @JmsListener(destination = "DESTINATION")
    public void receiveEvent() {
        Event event = (Event) jmsTemplate.receiveAndConvert("DESTINATION");
        System.out.println(event.toString());
    }    
}

但是当我 运行 接收方应用程序时,我快速且连续地遇到以下异常。

DefaultMessageListenerContainer-1] WARN  o.s.j.l.DefaultMessageListenerContainer - Execution of JMS message listener failed, and no ErrorHandler has been set.
org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'public void .service.MQServiceImpl.receiveEvent()' threw exception; nested exception is org.springframework.jms.MessageFormatException: JMSCC0053: An exception occurred deserializing a message, exception: 'java.lang.ClassNotFoundException: null class'.; nested exception is com.ibm.msg.client.jms.DetailedMessageFormatException: JMSCC0053: An exception occurred deserializing a message, exception: 'java.lang.ClassNotFoundException: null class'.
It was not possible to deserialize the message because of the exception shown.
Examine the linked exception for details of the error.

Caused by: org.springframework.jms.MessageFormatException: JMSCC0053: An exception occurred deserializing a message, exception: 'java.lang.ClassNotFoundException: null class'.; nested exception is com.ibm.msg.client.jms.DetailedMessageFormatException: JMSCC0053: An exception occurred deserializing a message, exception: 'java.lang.ClassNotFoundException: null class'.
It was not possible to deserialize the message because of the exception shown.
Examine the linked exception for details of the error.

我搜索了日志,但 none 这些答案对我有帮助。如果有人有解决此问题的想法,我将不胜感激。

更新

在发送者和接收者应用程序中,事件class是这样的。

@Data
public class Event implements Serializable {

    private static final long serialVersionUID = 2529600986924604571L;

    private String messageId;
    private String issuer;
    private EventType type;
    private EventName name;
    private Map<String, Object> argument;
    private LocalDateTime dateTime;
}

正如评论中所暗示的那样,您的 Event class 需要是可序列化的,看起来确实如此,监听器代码应该类似于:

@JmsListener(destination = "DESTINATION")
public void receiveEvent(Event event) {
   ...

Spring 将负责序列化对象作为 @JmsListener 注释的一部分。

尽管硬编码目的地并不好,您应该从 application.properties 中提取它。

Update If you are still getting a ClassNotFoundException then the serialisation that is being triggered is unable to find the classes. If your code is compiling then you probably have a class Event in your class path, but for some reason it isn't being recognised as compatible with the object that the receiving app is expecting.

从表面上看,您似乎拥有正确的 Event 对象,但是具有相同属性和相同 serialVersionUID 的 class 需要存在于 sender 和接收者代码。如果您对其中一个进行了更改,那么另一个也必须存在。强制执行此操作的最简单方法是将 class 放入两个应用程序都使用的 .jar 中。如果你有 Event class 是不同的发送方和接收方包,那么它会被认为是不同的 class.

如果您添加 @data 注释,spring 将为您处理很多序列化样板文件。例如

import lombok.Data;

@Data 
public class Event implements Serializable {    
   ... 

如果仍然无效,那么您可以选择接收 ObjectMessage 并自行执行序列化。您可能会发现 spring 自动序列化失败的原因。

EG.

import javax.jms.ObjectMessage; 
import java.io.Serializable;

@JmsListener(destination = "DESTINATION") 
public void receiveEvent(ObjectMessage message) {    
   Serializable serObj = message.getObject();    
   try {
      Event event = (Event) serObj;
      ...    
   } catch (ClassCastException e) {
      ...    
   }    
   ...

几天后,我找到了答案。我应该将 Event 对象转换为 JSON,然后从发送方应用程序发送它并从发送方接收 JSON 并将其转换为 Event 对象。实际上,我们不能直接通过MQ发送或接收对象。

发件人

  String stringEvent = objectMapper.writeValueAsString(EVENT_OBJ);
  jmsTemplate.convertAndSend(SEND_QUEUE_NAME, stringEvent);

接收器

  @Override
    @JmsListener(destination = "${mq.receive_queue}")
    public void receive(Message message) {
        try {
            String jsonEvent = ((TextMessage) message).getText();
            Event event = objectMapper.readValue(jsonEvent, Event.class);
        } catch (JMSException | IOException e) {
            e.printStackTrace();
        }
    }