springboot整合activemq

1 篇文章 0 订阅

1.依赖

  <!--activeMQ-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <!--使用线程池加上这个-->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
        </dependency>

配置

#activemq 配置
spring.activemq.broker-url=tcp://127.0.0.1:61616
# 在考虑结束之前等待的时间
#spring.activemq.close-timeout=15s
# 默认代理URL是否应该在内存中。如果指定了显式代理,则忽略此值。
spring.activemq.in-memory=true 
# 是否在回滚回滚消息之前停止消息传递。这意味着当启用此命令时,消息顺序不会被保留。
spring.activemq.non-blocking-redelivery=false
# 等待消息发送响应的时间。设置为0等待永远。
spring.activemq.send-timeout=0
#默认情况下activemq提供的是queue模式,若要使用topic模式需要配置下面配置
spring.jms.pub-sub-domain=true
#账号
spring.activemq.user=admin
# 密码
spring.activemq.password=admin
# 是否信任所有包
#spring.activemq.packages.trust-all=
# 要信任的特定包的逗号分隔列表(当不信任所有包时)
#spring.activemq.packages.trusted=
# 当连接请求和池满时是否阻塞。设置false会抛“JMSException异常”。
#spring.activemq.pool.block-if-full=true
# 如果池仍然满,则在抛出异常前阻塞时间。
#spring.activemq.pool.block-if-full-timeout=-1ms
# 是否在启动时创建连接。可以在启动时用于加热池。
#spring.activemq.pool.create-connection-on-startup=true
# 是否用Pooledconnectionfactory代替普通的ConnectionFactory。
#spring.activemq.pool.enabled=false
# 连接过期超时。
#spring.activemq.pool.expiry-timeout=0ms
# 连接空闲超时
#spring.activemq.pool.idle-timeout=30s
# 连接池最大连接数
#spring.activemq.pool.max-connections=1
# 每个连接的有效会话的最大数目。
#spring.activemq.pool.maximum-active-session-per-connection=500
# 当有"JMSException"时尝试重新连接
#spring.activemq.pool.reconnect-on-exception=true
# 在空闲连接清除线程之间运行的时间。当为负数时,没有空闲连接驱逐线程运行。
#spring.activemq.pool.time-between-expiration-check=-1ms
# 是否只使用一个MessageProducer
#spring.activemq.pool.use-anonymous-producers=true

2.activemq有两种方式,点对点(队列)模式,和发布订阅(topic)模式

      当spring.jms.pub-sub-domain=true是true表示支持topic模式,默认是false,支持点对点,如果true的前提下,没有配置 containerFactory = "jmsListenerContainerQueue",是不支持点对点模式的,我这边测试是没收到队列的消息.最好的方式就是队列设置队列的factory,topic设置topic的factory,下面说的不能用是指消费者收不到消息

3.消息生产者

package com.alimama.server.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alimama.api.enums.TopicEnum;
import com.alimama.api.service.IMqMessageProducerService;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.jms.*;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by PengWX on 2019/7/22.
 */
@Service("mqMessageProducerService")
public class MqMessageProducerServiceImpl implements IMqMessageProducerService {
    private static final Logger LOGGER = LoggerFactory.getLogger(MqMessageProducerServiceImpl.class);

    private Executor executor = new ThreadPoolExecutor(1, 10, 1, TimeUnit.DAYS, new LinkedBlockingQueue<Runnable>(), new ThreadPoolExecutor.CallerRunsPolicy());

    @Autowired
    private JmsTemplate jmsTemplate;

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;


    /**
     * 点对点和发布订阅都可以用
     * @param topic
     * @param message
     */
    @Override
    public void oldSend(TopicEnum topic, String message) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                jmsTemplate.send(topic.getKey(), new MessageCreator() {
                    @Override
                    public Message createMessage(Session session) throws JMSException {
                        TextMessage tm = session.createTextMessage();
                        tm.setText(JSON.toJSONString(message, SerializerFeature.WriteClassName));
                        LOGGER.info("send message to topic:" + topic.getKey() + ",content:" + message);
                        return tm;
                    }
                });
            }
        });
    }

    /**
     * 发布订阅模式,配置spring.jms.pub-sub-domain=true且如果消费者没有配置containerFactory的条件下,在点对点模式不能用.
     * @param topic
     * @param message
     */
    @Override
    public void send(TopicEnum topic, String message) {
        if (!StringUtils.isEmpty(message)) {
            executor.execute(new Runnable() {
                @Override
                public void run() {

                    /**
                     * 将接受到的消息及消息模式(topic或queue)放到队列里面,然后消费
                     * 者只需要正确的添加注解@JmsListener(destination = "目的地"),监听队列消息就会主动获取
                     */
                    ActiveMQTopic mqTopic = new ActiveMQTopic(topic.getKey());
                    jmsMessagingTemplate.convertAndSend(mqTopic, message);
                }
            });
        }
    }

    /**
     * 点对点模式,spring.jms.pub-sub-domain=false且消费者没有配置containerFactory的条件下,发布订阅模式不能用
     * @param queueName
     * @param message
     */
    @Override
    public void sendQueue(String queueName, String message) {
        if (!StringUtils.isEmpty(message)) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    Destination queue = new ActiveMQQueue(queueName);
                    jmsMessagingTemplate.convertAndSend(queue, message);
                }
            });
        }
    }

}

4.消息消费者

package com.alimama.server.service;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.Serializable;

/**
 * mq消息接收,需要加上@Component
 * Created by PengWX on 2019/7/22.
 */
@Component
public class MqMessageComsumer {


    /*
     * 监听和读取消息,如果spring.jms.pub-sub-domain=true此时是topic模式且没有配置 
     *containerFactory = "jmsListenerContainerTopic",这两个消费者都会重复消费消息, 设置对应 
     *的factory才能收对应的消息
     */
    @JmsListener(destination = "cheguo.queues.loan.test")
    public void messageComsumer(String message) {
        System.out.println("===============================================");
        System.out.println("接受到1:" + message);
        System.out.println("===============================================");
        //TODO something
    }
    /*
     * 监听和读取消息,如果spring.jms.pub-sub-domain=true且没有配置containerFactory = 
     *"jmsListenerContainerQueue",topic
     * 模式下这两个都会重复消费消息,设置对应的factory才能收对应的消息,如果spring.jms.pub-sub- 
     *domain=false,那么是点对点模式,这个时候不管几个消费者都只有一个消费者消费消息,不管有没有 
     *containerFactory = 
     *"jmsListenerContainerQueue"
     */
    @JmsListener(destination = "cheguo.queues.loan.test")
    public void messageComsumer1(String message) {
        System.out.println("===============================================");
        System.out.println("接受到2:" + message);
        System.out.println("===============================================");
        //TODO something
    }

   
}
#默认情况下activemq提供的是queue模式,若要使用topic模式需要配置下面配置
#spring.jms.pub-sub-domain=true

这个被注释的时候打印信息

activemq配置奉上

package com.alimama.server.config;

import com.alimama.api.enums.TopicEnum;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;

import javax.jms.Queue;
import javax.jms.Topic;

/**
 * Created by PengWX on 2019/7/23.
 */
@Configuration
public class ActiveMQConfig {
    @Value("${spring.activemq.user}")
    private String usrName;

    @Value("${spring.activemq.password}")
    private  String password;

    @Value("${spring.activemq.broker-url}")
    private  String brokerUrl;

    @Bean
    public Queue queue(){
        return new ActiveMQQueue("cheguo.queues.loan.test");
    }

    @Bean
    public Topic topic(){
        return new ActiveMQTopic(TopicEnum.LOAN.getKey());
    }

    @Bean
    public ActiveMQConnectionFactory connectionFactory() {
        return new ActiveMQConnectionFactory(usrName, password, brokerUrl);
    }

/**
*设置queue工厂
*/

    @Bean
    public JmsListenerContainerFactory<?> jmsListenerContainerQueue(ActiveMQConnectionFactory connectionFactory){
        DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
        bean.setConnectionFactory(connectionFactory);
        return bean;
    }

/**
*设置topic工程
*/
    @Bean
    public JmsListenerContainerFactory<?> jmsListenerContainerTopic(ActiveMQConnectionFactory connectionFactory){
        DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
        //设置为发布订阅方式, 默认情况下使用的生产消费者方式
        bean.setPubSubDomain(true);
        bean.setConnectionFactory(connectionFactory);
        return bean;
    }
}

上面的消费者只能在对应的模式下收取对应消息

要想topic和queue一起,现在说的是使用  jmsMessagingTemplate就需要在消费者上面加上对应的 containerFactory,正确代码

 /*
     * 监听和读取消息
     */
    @JmsListener(destination = "cheguo.queues.loan.test",containerFactory = "jmsListenerContainerTopic")
    public void messageComsumer(String message) {
        System.out.println("===============================================");
        System.out.println("接受到1:" + message);
        System.out.println("===============================================");
        //TODO something
    }
    /*
     * 监听和读取消息,只接受queue消息
     */
    @JmsListener(destination = "cheguo.queues.loan.test",containerFactory = "jmsListenerContainerQueue")
    public void messageComsumer1(String message) {
        System.out.println("===============================================");
        System.out.println("接受到2:" + message);
        System.out.println("===============================================");
        //TODO something
    }

总结:

 使用jmsMessagingTemplate

1. 如果

#默认情况下activemq提供的是queue模式,若要使用topic模式需要配置下面配置
spring.jms.pub-sub-domain=true

  此时是发布订阅模式,消费者没有指定containerFactory 那么两个消费者都会消费消息,需要设置queue和topic的containerFactory才能收取对应的消息.

2.如果

 #默认情况下activemq提供的是queue模式,若要使用topic模式需要配置下面配置

spring.jms.pub-sub-domain=false

 或者不配置这个的情况下,此时是点对点模式,就算没有设置containerFactory 消息依然只有一个消费者会消费,最好是设置好containerFactory

需要在active的那个配置类里面的topic的工厂里面设置  bean.setPubSubDomain(true);不然不管有没有在application.propeties里面设置spring.jms.pub-sub-domain=,也不管设置的什么.topic都收不到消息,要想两种模式都可以,配置文件要加上这个spring.jms.pub-sub-domain=true,在activemqConfig里面的topic的factory加上bean.setPubSubDomain(true)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值