【ActiveMQ】Part4 - ActiveMQ整合Spring

目录结构

在这里插入图片描述

代码

代码用Junit测试,省略web.xml和tomcat相关的配置

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <Appenders>
        <Console name="STDOUT" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %-5p [%t] %C{2} (%F:%L) - %m%n"/>
        </Console>
    </Appenders>
    <Loggers>
        <Root level="info">
            <AppenderRef ref="STDOUT"/>
        </Root>
    </Loggers>
</Configuration>

pom.xml

<dependencies>
   <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.1.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jms</artifactId>
        <version>5.1.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.1.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>javax.jms</groupId>
        <artifactId>javax.jms-api</artifactId>
        <version>2.0.1</version>
    </dependency>
    <dependency>
        <groupId>org.apache.xbean</groupId>
        <artifactId>xbean-spring</artifactId>
        <version>4.6</version>
    </dependency>
    <dependency>
        <groupId>org.apache.activemq</groupId>
        <artifactId>activemq-client</artifactId>
        <version>5.15.9</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.0.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j-impl</artifactId>
        <version>2.11.0</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.16.22</version>
    </dependency>
</dependencies>

config.properties

#参考http://activemq.apache.org/failover-transport-reference.html
mq.url=failover:(tcp://127.0.0.1:61616,tcp://127.0.0.2:61616)?randomize=false
#用户名
mq.username=admin
#密码
mq.password=admin
#queue默认目的地名称
mq.queue=hello
#topic默认目的地名称
mq.topic=hello
#消息监听者 topic
mq.topic.listener=com.example.activemq.TopicMsgListener
#消息监听者 queue
mq.queue.listener=com.example.activemq.QueueMsgListener
#必须connection上仅仅有一个session相关联。如果存在多个session实例则无效
mq.alwaysSessionAsync=true
#是否支持批量确认消息
mq.optimizeAcknowledge=true
#异步发送消息
mq.useAsyncSend=true
#生产者发送消息的最大字节数,与使用异步参数同时使用
mq.producerWindowSize=1048576
#Session缓存数量
mq.sessionCacheSize=100
#传递的object包白名单,参考http://activemq.apache.org/objectmessage.html 
mq.trustedPackages=com.example.pojo

spring.xml

1、spring-mvc.xml

<?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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.example"/>
    <mvc:annotation-driven/>
</beans>

2、spring-activemq-parent.xml

<?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: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/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--引入配置-->
    <context:property-placeholder location="classpath:config.properties"/>

    <!--配置JMS连接工厂-->
    <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
        <property name="brokerURL" value="${mq.url}"/>
        <property name="userName" value="${mq.username}"/>
        <property name="password" value="${mq.password}"/>
        <property name="alwaysSessionAsync" value="${mq.alwaysSessionAsync}"/>
        <property name="optimizeAcknowledge" value="${mq.optimizeAcknowledge}"/>
        <property name="useAsyncSend" value="${mq.useAsyncSend}"/>
        <property name="producerWindowSize" value="${mq.producerWindowSize}"/>
        <property name="trustedPackages" value="${mq.trustedPackages}"/>
    </bean>

    <!--Spring管理连接工厂-->
    <bean id="cachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
        <property name="targetConnectionFactory" ref="connectionFactory"/>
        <!--session缓存数量-->
        <property name="sessionCacheSize" value="${mq.sessionCacheSize}"/>
    </bean>
</beans>

3、spring-activemq-producer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--公共配置-->
    <import resource="spring-activemq-parent.xml"/>

    <!--Queue 队列消息模板-->
    <bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="cachingConnectionFactory"/>
        <property name="pubSubDomain" value="false"/>
        <property name="sessionTransacted" value="true"/>
        <property name="defaultDestinationName" value="${mq.queue}"/>
    </bean>

    <!--Topic 发布/订阅消息模板-->
    <bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
        <constructor-arg ref="connectionFactory" />
        <property name="pubSubDomain" value="true" />
        <property name="sessionTransacted" value="true"/>
        <property name="defaultDestinationName" value="${mq.topic}"/>
    </bean>
</beans>

4、spring-activemq-consumer.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--公共配置-->
    <import resource="spring-activemq-parent.xml"/>

    <!--Queue 消费者监听容器-->
    <bean id="jmsQueueContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="cachingConnectionFactory"/>
        <property name="pubSubDomain" value="false"/>
        <property name="destinationName" value="${mq.queue}"/>
        <property name="messageListener">
            <bean class="${mq.queue.listener}"/>
        </property>
        <property name="sessionTransacted" value="false"/>
    </bean>

    <!-- Topic 消息监听容器 -->
    <bean id="jmsTopicContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="cachingConnectionFactory"/>
        <property name="pubSubDomain" value="true"/>
        <property name="destinationName" value="${mq.topic}"/>
        <property name="messageListener">
            <bean class="${mq.topic.listener}"/>
        </property>
        <!-- 事务控制(开启后会显著影响消费者性能),默认为false,超过重发次数(缺省为6次)后会发送到死信队列,默认为ActiveMQ.DLQ -->
        <property name="sessionTransacted" value="false"/>
    </bean>
</beans>

QueueMsgListener

package com.example.activemq;

import lombok.extern.log4j.Log4j2;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@Log4j2
public class QueueMsgListener implements MessageListener {

    @Override
    public void onMessage(Message message) {
        try {
            TextMessage msg = (TextMessage) message;

            if (log.isInfoEnabled()){
                log.info("Queue消息:{}", msg.getText());
            }
        } catch (JMSException e) {
            log.error("接收JMS Queue消息失败", e);
        }
    }
}

TopicMsgListener

package com.example.activemq;

import lombok.extern.log4j.Log4j2;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

@Log4j2
public class TopicMsgListener implements MessageListener {

    @Override
    public void onMessage(Message message) {
        try {
            TextMessage textMessage = (TextMessage) message;

            String msg = textMessage.getText();

            if (log.isInfoEnabled()){
                log.info("Topic消息:{}", msg);
            }
        } catch (JMSException e) {
            log.error("接收JMS Topic消息失败", e);
        }
    }
}

ActiveMQUtil

package com.example.activemq;

import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
import javax.jms.Destination;

@Log4j2
@Component
public class ActiveMQUtil {
    /**
     * Spring JMS Topic 操作模板
     */
    private static JmsTemplate jmsTopicTemplate;
    /**
     * Spring JMS Queue 操作模板
     */
    private static JmsTemplate jmsQueueTemplate;

    @Autowired
    @Qualifier("jmsTopicTemplate")
    public void setJmsTopicTemplate(JmsTemplate jmsTopicTemplate) {
        ActiveMQUtil.jmsTopicTemplate = jmsTopicTemplate;
    }

    @Autowired
    @Qualifier("jmsQueueTemplate")
    public void setJmsQueueTemplate(JmsTemplate jmsQueueTemplate) {
        ActiveMQUtil.jmsQueueTemplate = jmsQueueTemplate;
    }

    public static JmsTemplate getJmsTopicTemplate() {
        return jmsTopicTemplate;
    }

    public static JmsTemplate getJmsQueueTemplate() {
        return jmsQueueTemplate;
    }

    /**
     * 发送JMS Topic消息,使用默认目的地
     *
     * @param message
     */
    public static void sendTopicMessage(Object message) {
        try {
            jmsTopicTemplate.convertAndSend(message);
        } catch (Exception e) {
            log.error("发送JMS Topic消息失败", e);
        }
    }

    /**
     * 发送JMS Topic消息
     *
     * @param destinationName
     * @param message
     */
    public static void sendTopicMessage(String destinationName, final Object message) {
        try {
            jmsTopicTemplate.convertAndSend(destinationName, message);
        } catch (Exception e) {
            log.error("发送JMS Topic消息失败", e);
        }
    }

    /**
     * 发送JMS Topic消息
     *
     * @param destination
     * @param message
     */
    public static void sendTopicMessage(Destination destination, final Object message) {
        try {
            jmsTopicTemplate.convertAndSend(destination, message);
        } catch (Exception e) {
            log.error("发送JMS Topic消息失败", e);
        }
    }

    /**
     * 发送JMS Queue消息,使用默认目的地
     *
     * @param message
     */
    public static void sendQueueMessage(Object message) {
        try {
            jmsQueueTemplate.convertAndSend(message);
        } catch (Exception e) {
            log.error("发送JMS Queue消息失败", e);
        }
    }

    /**
     * 发送JMS Queue消息
     *
     * @param destinationName
     * @param message
     */
    public static void sendQueueMessage(String destinationName, final Object message) {
        try {
            jmsQueueTemplate.convertAndSend(destinationName, message);
        } catch (Exception e) {
            log.error("发送JMS Queue消息失败", e);
        }
    }

    /**
     * 发送JMS Queue消息
     *
     * @param destination
     * @param message
     */
    public static void sendQueueMessage(Destination destination, final Object message) {
        try {
            jmsQueueTemplate.convertAndSend(destination, message);
        } catch (Exception e) {
            log.error("发送JMS Queue消息失败", e);
        }
    }
}

User

用来测试发送和接收Object类型

package com.example.pojo;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;

@Getter
@Setter
@AllArgsConstructor
@ToString
public class User implements Serializable {
    private static final long serialVersionUID = 4560591454591857339L;
    private String name;
    private String password;
}
ActiveMQObjectMessage objectMessage = (ActiveMQObjectMessage) message;
User user = (User) objectMessage.getObject();

ReceiveTest

package com.example;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.IOException;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring/spring-activemq-consumer.xml"})
public class ReceiveTest {

    @Test
    public void run() throws IOException {
        // 阻塞当前代码
        System.in.read();
    }
}

SendTest

package com.example;

import com.example.activemq.ActiveMQUtil;
import lombok.extern.log4j.Log4j2;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@Log4j2
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring/spring-activemq-producer.xml","classpath:spring/spring-mvc.xml"})
public class SendTest {
    @Test
    public void sendQueue(){
        ActiveMQUtil.sendQueueMessage("只有一个能接收到");
    }

    @Test
    public void sendTopic(){
        ActiveMQUtil.sendTopicMessage("都能接收到");
    }
}

测试

Queue

先跑起来几个ReceiveTest实例
在这里插入图片描述
发送一条消息
在这里插入图片描述
其中一个接收到消息并输出

Topic

在这里插入图片描述
都接收到了消息

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值