一、出现以下异常时,需要注意,receive获取消息时不可有返回值,否则循环报此异常
Execution of JMS message listener failed, and no ErrorHandler has been set.
2019-09-17 16:05:06.651 WARN 26416 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer : Execution of JMS message listener failed, and no ErrorHandler has been set.
org.springframework.jms.listener.adapter.ReplyFailureException: Failed to send reply with payload []; nested exception is javax.jms.InvalidDestinationException: Cannot determine response destination: Request message does not contain reply-to destination, and no default response destination set.
at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener.handleResult(AbstractAdaptableMessageListener.java:285) ~[spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:79) ~[spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:736) ~[spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:696) ~[spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:674) ~[spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:318) [spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:257) [spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1189) [spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1179) [spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1076) [spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_221]
Caused by: javax.jms.InvalidDestinationException: Cannot determine response destination: Request message does not contain reply-to destination, and no default response destination set.
at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener.getResponseDestination(AbstractAdaptableMessageListener.java:393) ~[spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener.getResponseDestination(AbstractAdaptableMessageListener.java:366) ~[spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
at org.springframework.jms.listener.adapter.AbstractAdaptableMessageListener.handleResult(AbstractAdaptableMessageListener.java:281) ~[spring-jms-5.1.2.RELEASE.jar:5.1.2.RELEASE]
... 10 common frames omitted
异常源码如下:
@JmsListener(destination="mytopic")
//未加@SendTo注解引发异常
public String receviceTopicMsg(TextMessage tm) {
String str = "";
try {
str = tm.getText();
System.out.println("topic"+ tm.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return str;
}
正常是这样:
@JmsListener(destination="mytopic")
//注:可有返回值,可添加@SendTo注解解决,如果不想加此注解,就必须为void,感谢qq_34651592指教
@SendTo
public String receviceTopicMsg(TextMessage tm) {
try {
System.out.println("topic"+ tm.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
二、发布订阅模式需要注意的是Springboot + activeMQ默认情况下是不开启的,需要在消费者配置文件中开启
server:
port: 8070
spring:
activemq:
broker-url: tcp://127.0.0.1:61616
##此处配置项便是开启发布订阅模式,开启后队列模式(点对点)不可用
jms:
pub-sub-domain: true
queue: myqueue
topic: mytopic
完整的整合案例:
首先是在POM.xml加入依赖文件
org.springframework.boot
spring-boot-starter-parent
2.1.0.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-activemq
org.springframework.boot
spring-boot-devtools
org.springframework.boot
spring-boot-maven-plugin
生产者配置文件:
server:
port: 8060
spring:
activemq:
broker-url: tcp://127.0.0.1:61616
queue: myqueue
topic: mytopic
配置类
/**
* 队列模式,点对点配置类,一条消息只能被一个消费者获取
* @ClassName: QueueConfig
* @Description: TODO
* @author: dufen
* @date: 2019年9月17日 下午2:38:34
*/
@Component
public class QueueConfig {
@Value(value="${queue}")
private String queue;
@Bean
public Queue getQueue() {
return new ActiveMQQueue(queue);
}
}
/**
* 发布订阅者模式,一条消息可以被多人获取,前提是必须先开启消费者,再开启生产者,否则,消息会被作废
* @ClassName: TopicConfig
* @Description: TODO
* @author: dufen
* @date: 2019年9月17日 下午4:16:57
*/
@Component
public class TopicConfig {
@Value(value="${topic}")
private String topic;
@Bean
public Topic getTopic() {
return new ActiveMQTopic(topic);
}
}
业务层
/**
* 发送信息业务层
* @ClassName: SendMessageService
* @Description: TODO
* @author: dufen
* @date: 2019年9月17日 下午4:18:38
*/
@Component
public class SendMessageService {
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
@Autowired
private Queue queue;
@Autowired
private Topic topic;
/**
* 发送队列消息
* @Title: sendQueueMsg
* @Description: TODO
* @param msg
* @return: void
*/
public void sendQueueMsg(String msg) {
jmsMessagingTemplate.convertAndSend(queue, msg);
}
/**
* 发布订阅模式·发送消息
* @Title: sendTopicMsg
* @Description: TODO
* @param msg
* @return: void
*/
public void sendTopicMsg(String msg) {
jmsMessagingTemplate.convertAndSend(topic, msg);
}
}
控制层
/**
* 控制层
* @ClassName: MsgContoller
* @Description: TODO
* @author: dufen
* @date: 2019年9月17日 下午4:20:31
*/
@RestController
public class MsgContoller {
@Autowired
private SendMessageService sendMessageService;
@RequestMapping("/sendQueueMsg")
public String sendQueueMsg(@RequestParam(name="msg")String msg) {
sendMessageService.sendQueueMsg(msg);
return msg;
}
@RequestMapping("/sendTopicMsg")
public String sendTopicMsg(@RequestParam(name="msg")String msg) {
sendMessageService.sendTopicMsg(msg);
return msg;
}
}
生产者服务器启动类
@SpringBootApplication
public class ProviderApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(ProviderApp.class, args);
}
}
消费者配置文件
server:
port: 8070
spring:
activemq:
broker-url: tcp://127.0.0.1:61616
#此处开启发布订阅者模式,开启后,队列模式无法获取消息
jms:
pub-sub-domain: true
/**
* 消费者监听获取消息类
* @ClassName: ReceiveMessageService
* @Description: TODO
* @author: dufen
* @date: 2019年9月17日 下午4:26:55
*/
@Component
public class ReceiveMessageService {
@JmsListener(destination="myqueue")
//注:此处方法不可有返回值
public void receviceMsg(TextMessage tm) {
String str = "";
try {
str = tm.getText();
System.out.println("queue"+ tm.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@JmsListener(destination="mytopic")
//注:此处方法不可有返回值
public void receviceTopicMsg(TextMessage tm) {
String str = "";
try {
str = tm.getText();
System.out.println("topic"+ tm.getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@SpringBootApplication
public class ConsumerApp {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(ConsumerApp.class, args);
}
}
整合完成,还有定时调度,
直接在发送消息类名之上加上@EnableScheduling,
发送消息的方法之上加上注解@Scheduled(fixedDelay = 5000),fixedDelay单位为毫秒