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();
            }
        }
    }
}

  

 

posted @   变体精灵  阅读(212)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示