Spring整合ActiveMQ
1、导入依赖
1 2 3 4 5 6 7 8 9 10 11 12 | <!--ActiveMQ连接池--> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-pool</artifactId> <version> 5.15 . 5 </version> </dependency> <!-- spring支持jms的包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jms</artifactId> <version>${spring-version}</version> </dependency> |
2、Spring的配置文件中添加如下配置(我这里Spring的配置文件是 /conf/spring/applicationContext.xml)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | <?xml version= "1.0" encoding= "UTF-8" ?> <beans xmlns= "http://www.springframework.org/schema/beans" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:tx= "http://www.springframework.org/schema/tx" xmlns:context= "http://www.springframework.org/schema/context" xsi:schemaLocation="http: //www.springframework.org/schema/beans http: //www.springframework.org/schema/beans/spring-beans.xsd http: //www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http: //www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--配置包扫描,spring扫描该包下面除了 @Controller 之外的所有注解--> <context:component-scan base- package = "com.bocom" > <context:exclude-filter type= "annotation" expression= "org.springframework.stereotype.Controller" /> </context:component-scan> <!--ActiveMQ与Spring整合相关配置--> <bean id= "connectionFactory" class = "org.apache.activemq.pool.PooledConnectionFactory" destroy-method= "stop" > <property name= "connectionFactory" > <!--真正可以生产Connection的ConnectionFactory,由对应的JMS服务商提供--> <bean class = "org.apache.activemq.ActiveMQConnectionFactory" > <property name= "brokerURL" value= "tcp://192.168.229.129:61616" /> </bean> </property> <property name= "maxConnections" value= "100" /> </bean> <!--这个是队列目的地,点对点的Queue--> <bean id= "destinationQueue" class = "org.apache.activemq.command.ActiveMQQueue" > <!--通过构造注入Queue名--> <constructor-arg index= "0" value= "spring-active-queue" /> </bean> <!--这个是队列目的地,发布订阅的主题Topic--> <bean id= "destinationTopic" class = "org.apache.activemq.command.ActiveMQTopic" > <!--通过构造注入Topic名--> <constructor-arg index= "0" value= "spring-active-topic" /> </bean> <!--Spring提供的JMS工具类,他可以进行消息发送,接收等--> <bean id= "jmsTemplate" class = "org.springframework.jms.core.JmsTemplate" > <!--传入连接工厂--> <property name= "connectionFactory" ref= "connectionFactory" /> <!--传入目的地--> <property name= "defaultDestination" ref= "destinationQueue" /> <!--消息自动转换器--> <property name= "messageConverter" > <bean class = "org.springframework.jms.support.converter.SimpleMessageConverter" /> </property> </bean> </beans> |
3、队列
模式一:生产者发送队列消息至缺省的队列,消费者从缺省的队列中获取消息
1、生产者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @Service public class JmsProducer { @Autowired private JmsTemplate jmsTemplate; public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "/conf/spring/applicationContext.xml" ); JmsProducer jmsProducer = (JmsProducer) context.getBean( "jmsProducer" ); for ( int i = 1 ; i < 7 ; i++) { jmsProducer.jmsTemplate.send( new MessageCreator() { @Override public Message createMessage(Session session) throws JMSException { TextMessage textMessage = session.createTextMessage( "queue:::" + UUID.randomUUID().toString().replace( "-" , "" )); return textMessage; } }); } System.out.println( "JmsProducer send message ok!!!" ); } } |
执行生产者代码之后,可以看出,生产者将消息发送至MQ服务器,队列的名称为 spring-active-queue,这个队列的名称就是我们在Spring的配置文件中配置的缺省的Destination
2、消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Service public class JmsConsumer { @Autowired private JmsTemplate jmsTemplate; public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "/conf/spring/applicationContext.xml" ); JmsConsumer jmsConsumer = (JmsConsumer) context.getBean( "jmsConsumer" ); while ( true ) { String textMessage = (String) jmsConsumer.jmsTemplate.receiveAndConvert(); System.out.println( "接收到的消息是:" + textMessage); } } } |
执行完消费者代码之后,我们可以看到,消息已经被消费了.
3、控制台
虽然这个时候,生产者发送完了消息,消费者也消费完了消息,但是生产者和消费者的程序还是处于执行的状态,并没有断开.
模式二:生产者发送队列消息至指定的队列,消费者从指定的队列中获取消息
1、生产者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @Service public class JmsProducer { @Autowired private JmsTemplate jmsTemplate; public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "/conf/spring/applicationContext.xml" ); JmsProducer jmsProducer = (JmsProducer) context.getBean( "jmsProducer" ); // 使用该代码,可以让生产者将队列消息发送到指定名称的队列中,而不是发送达到缺省的Destination jmsProducer.jmsTemplate.setDefaultDestinationName( "spring-active-queue-dynamic" ); for ( int i = 1 ; i < 7 ; i++) { jmsProducer.jmsTemplate.send( new MessageCreator() { @Override public Message createMessage(Session session) throws JMSException { TextMessage textMessage = session.createTextMessage( "queue:::dynamic" + UUID.randomUUID().toString().replace( "-" , "" )); return textMessage; } }); } System.out.println( "JmsProducer send message ok!!!" ); } } |
执行生产者代码之后,可以看到,我们的消息不再发送到Spring配置文件中配置的缺省队列(spring-active-queue)中了,而是发送到了我们自己指定的队列(spring-active-queue-dynamic)中了
2、消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @Service public class JmsConsumer { @Autowired private JmsTemplate jmsTemplate; public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "/conf/spring/applicationContext.xml" ); JmsConsumer jmsConsumer = (JmsConsumer) context.getBean( "jmsConsumer" ); while ( true ) { // 可以让消费者从指定的队列中获取消息(队列的名称为:spring-active-queue-dynamic),而不是从缺省的Destination中获取 jmsConsumer.jmsTemplate.setDefaultDestinationName( "spring-active-queue-dynamic" ); String textMessage = (String) jmsConsumer.jmsTemplate.receiveAndConvert(); System.out.println( "接收到的消息是:" + textMessage); } } } |
消费者指定代码之后,可以从指定的队列(spring-active-queue-dynamic)中消费消息,不再从缺省的Destination中消费消息了.
d
3、控制台
4、主题
在发送主题消息之前,需要将上面的Spring的配置文件的Destination切换到主题模式
1 2 3 4 5 6 7 8 9 10 11 | // 之前缺省的Destination是队列,这里改为主题 <bean id= "jmsTemplate" class = "org.springframework.jms.core.JmsTemplate" > <!--传入连接工厂--> <property name= "connectionFactory" ref= "connectionFactory" /> <!--传入目的地--> <property name= "defaultDestination" ref= "destinationTopic" /> <!--消息自动转换器--> <property name= "messageConverter" > <bean class = "org.springframework.jms.support.converter.SimpleMessageConverter" /> </property> </bean> |
模式一:生产者发送主题消息至缺省的topic,消费者从缺省的topic中获取消息
由于topic默认不是持久化的,所以我们这里要先运行消费者,就是做一个注册的操作
1、消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Service public class JmsConsumer { @Autowired private JmsTemplate jmsTemplate; public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "/conf/spring/applicationContext.xml" ); JmsConsumer jmsConsumer = (JmsConsumer) context.getBean( "jmsConsumer" ); while ( true ) { String textMessage = (String) jmsConsumer.jmsTemplate.receiveAndConvert(); System.out.println( "接收到的消息是:" + textMessage); } } } |
运行完消费者之后,可以看到,消费者在名称为:spring-active-topic的主题上等待消费消息
2、生产者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @Service public class JmsProducer { @Autowired private JmsTemplate jmsTemplate; public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "/conf/spring/applicationContext.xml" ); JmsProducer jmsProducer = (JmsProducer) context.getBean( "jmsProducer" ); for ( int i = 1 ; i < 7 ; i++) { jmsProducer.jmsTemplate.send( new MessageCreator() { @Override public Message createMessage(Session session) throws JMSException { TextMessage textMessage = session.createTextMessage( "topic:::" + UUID.randomUUID().toString().replace( "-" , "" )); return textMessage; } }); } System.out.println( "JmsProducer send message ok!!!" ); } } |
生产者运行完之后,可以看到6条topic类型的消息,都发送到了我们在Spring配置文件配置的缺省Destination中(spring-active-topic)
3、控制台
这里有一个问题,生产者生产了6条消息,但是消费者只消费了4条消息,有两条消息没有被消费到,我猜测是不是消费者没有持久化的原因,所以尝试着在消费者中加入以下代码,但是最后还是会有消息没有消费到,(暂时原因不明,以后再探究)
1 2 3 4 | // 尝试着能不能持久化 jmsConsumer.jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT); String textMessage = (String) jmsConsumer.jmsTemplate.receiveAndConvert(); System.out.println( "接收到的消息是:" + textMessage); |
模式二:生产者发送主题消息至指定的topic,消费者从指定的topic中获取消息
1、消费者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @Service public class JmsConsumer { @Autowired private JmsTemplate jmsTemplate; public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "/conf/spring/applicationContext.xml" ); JmsConsumer jmsConsumer = (JmsConsumer) context.getBean( "jmsConsumer" ); while ( true ) { //可以让消费者从指定的队列中获取消息(队列的名称为:spring-active-queue-dynamic),而不是从缺省的Destination中获取 ActiveMQTopic activeMQTopic = new ActiveMQTopic( "spring-active-queue-dynamic" ); jmsConsumer.jmsTemplate.setDefaultDestination(activeMQTopic); String textMessage = (String) jmsConsumer.jmsTemplate.receiveAndConvert(); System.out.println( "接收到的消息是:" + textMessage); } } } |
执行完消费者代码之后,可以看到消费者已经在等待名称为 spring-active-queue-dynamic的主题上的消息了,并不是使用spring配置文件中缺省的Destination
2、生产者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | @Service public class JmsProducer { @Autowired private JmsTemplate jmsTemplate; public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "/conf/spring/applicationContext.xml" ); JmsProducer jmsProducer = (JmsProducer) context.getBean( "jmsProducer" ); // 使用该代码,可以让生产者将队列消息发送到指定名称的队列中,而不是发送到缺省的Destination ActiveMQTopic activeMQTopic = new ActiveMQTopic( "spring-active-queue-dynamic" ); jmsProducer.jmsTemplate.setDefaultDestination(activeMQTopic); for ( int i = 1 ; i < 7 ; i++) { jmsProducer.jmsTemplate.send( new MessageCreator() { @Override public Message createMessage(Session session) throws JMSException { TextMessage textMessage = session.createTextMessage( "topic:::dynamic" + UUID.randomUUID().toString().replace( "-" , "" )); return textMessage; } }); } System.out.println( "JmsProducer send message ok!!!" ); } } |
执行完生产者之后,发现6条消息确实发送到了指定的主题 spring-active-topic-dynamic上了
3、控制台
从MQ的管理界面和控制台上看到,我们总共发送了6条消息,只消费了3条消息,为什么剩下的3条消息没有消费到呢?
5、配置消费者的监听类
1、在spring的配置文件中加上这一段
1 2 3 4 5 6 7 | <!--配置监听程序--> <bean id= "jmsContainer" class = "org.springframework.jms.listener.DefaultMessageListenerContainer" > <property name= "connectionFactory" ref= "connectionFactory" ></property> <property name= "destination" ref= "destinationTopic" ></property> <!--自定义消息监听类MyMessageListener implements MessageListener接口--> <property name= "messageListener" ref= "myMessageListerer" ></property> </bean> |
2、消息监听类(有了消息监听类之后就不需要启动消费者了,直接可以获取消息,因为spring的配置文件已经启动了消费者)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Component ( "myMessageListerer" ) public class MyMessageListerer implements MessageListener { @Override public void onMessage(Message message) { if (message != null && message instanceof TextMessage) { TextMessage textMessage = (TextMessage) message; try { System.out.println( "接收到的消息是:" + textMessage.getText()); } catch (JMSException e) { e.printStackTrace(); } } } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?