用于测试 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();
}
}
我有两个用于测试 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 classEvent
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();
}
}