Springboot集成Activemq,含queue和topic

vigor512 2022-10-20 19:11:59

1.下载安装Activemq

下载地址: http://activemq.apache.org/download.html

下载完成后,进行Activemq配置

如上所示,做了mysql持久化,因此需要创建数据库activemq 

根据系统win32和win64进入对于的目录进行启动

 2.Springboot配置

pom文件

bootstrap.yml

 

 

 代码主要分为三部分

创建配置类ActivemqConfig

package com.ruoyi.activemq.config;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.ActiveMQPrefetchPolicy;
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.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.config.SimpleJmsListenerContainerFactory;
import org.springframework.jms.core.JmsMessagingTemplate;

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

/**
 * 创建配置类ActivemqConfig,读取yml中的内容,并且创建对象
 */
@Configuration
public class ActivemqConfig implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(ActivemqConfig.class);


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

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

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

    @Value("${spring.activemq.queue-name}")
    private String queueName;

    @Value("${spring.activemq.topic-name}")
    private String topicName;

    /**
     * 初始化队列配置
     * @return
     */
    @Bean(name = "queue")
    public Queue queue() {
        return new ActiveMQQueue(queueName);
    }

    /**
     * 初始化主题配置
     * @return
     */
    @Bean(name = "topic")
    public Topic topic() {
        return new ActiveMQTopic(topicName);
    }

    /**
     * mq连接对象
     * @return
     */
    @Bean
    public ConnectionFactory connectionFactory() {
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(username, password, brokerUrl);
        //解决多个线程从activeMQ中取消息,随着业务的扩大,该机器占用的网络带宽越来越高
        ActiveMQPrefetchPolicy activeMQPrefetchPolicy = new ActiveMQPrefetchPolicy();
        activeMQPrefetchPolicy.setQueuePrefetch(1);
        activeMQConnectionFactory.setPrefetchPolicy(activeMQPrefetchPolicy);
        return activeMQConnectionFactory;
    }

    /**
     * mq消息模板
     * 多个线程从activeMQ中取消息,随着业务的扩大,该机器占用的网络带宽越来越高
     * 原因分析:
     * jmsTemplate实现机制是:每次调用receive()时都会创建一个新的consumer对象,用完即销毁。
     * activeMQ的prefetch机制
     * 每次consumer连接至MQ时,MQ预先存放许多message到消费者(前提是MQ中存在大量消息),预先存放message的数量取决于prefetchSize(默认为1000)。此机制的目的很显然,是想让客户端代码用一个consumer反复进行receive操作,这样能够大量提高出队性能
     * 每次jmsTemplate.receive(),都会产生1000个消息的网络流量,但是因为jmsTemplae并不会重用consumer,导致后面999个消息都被废弃
     *
     * 解决方案:
     * 1、若坚持使用jmsTemplate,需要设置prefetch值为1,相当于禁用了activeMQ的prefetch机制,反复调用jmsTemplate.receive()也不会有任何问题。但是会有资源浪费,因为要反复创建consumer并频繁与服务器进行数据通信,但在性能要求不高的应用中也不算什么问题。
     * 2、不使用jmsTemplate,手工创建一个consumer,并单线程反复使用它来receive(),此时可以充分利用prefetch机制。配合多线程的方式每个线程拥有自己的一个consumer,此时能够充分发挥MQ在大吞吐量时的速度优势。
     * @return
     */
    @Bean
    public JmsMessagingTemplate jmsMessageTemplate() {
        return new JmsMessagingTemplate(connectionFactory());
    }

    // 在Queue模式中,对消息的监听需要对containerFactory进行配置
    @Bean("queueListener")
    public JmsListenerContainerFactory<?> queueJmsListenerContainerFactory(ConnectionFactory connectionFactory) {
        SimpleJmsListenerContainerFactory factory = new SimpleJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setPubSubDomain(false);
        return factory;
    }

    //在Topic模式中,对消息的监听需要对containerFactory进行配置
    @Bean("topicListener")
    public JmsListenerContainerFactory<?> topicJmsListenerContainerFactory(ConnectionFactory connectionFactory) {
        SimpleJmsListenerContainerFactory factory = new SimpleJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setPubSubDomain(true);
        return factory;
    }

    /**
     * 实现CommandLineRunne接口,便于在实例化的时候能看到启动信息(不必须)
     * @param args
     * @throws Exception
     */
    @Override
    public void run(String... args) throws Exception {
        logger.info(this.getClass().getName() + " is running\n***************************");
    }
}

 生产者

package com.ruoyi.activemq.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

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

@RestController
@RequestMapping("/test")
public class ProducerController {
    @Autowired
    private Queue queue;

    @Autowired
    private Topic topic;

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    /**
     * 发送 队列消息
     * @return
     */
    @RequestMapping("/sendQueue")
    public String sendQueue(@RequestBody String str) {
        this.sendMessage(this.queue, str);
        return "队列消息发送成功!message=" + str;
    }

    /**
     * 异步发送
     * @return
     */
    @Async
    public ListenableFuture<Object> asyncSendQueue(@RequestBody String str) {
        try {
            // 发送消息
            this.sendQueue(str);
            // 返回成功的 Future
            return AsyncResult.forValue(null);
        } catch (Throwable ex) {
            // 返回异常的 Future
            return AsyncResult.forExecutionException(ex);
        }
    }

    /**
     * 发送 主题消息
     * @return
     */
    @RequestMapping("/sendTopic")
    public String sendTopic(@RequestBody String str) {
        this.sendMessage(this.topic, str);
        return "主题消息发送成功!message=" + str;
    }

    // 发送消息,destination是发送到的队列,message是待发送的消息
    private void sendMessage(Destination destination, final String message) {
        jmsMessagingTemplate.convertAndSend(destination, message);
    }

}
package com.ruoyi.activemq.controller;

import org.springframework.jms.annotation.JmsListener;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ConsumerController {
    @JmsListener(destination = "${spring.activemq.queue-name}", containerFactory = "queueListener")
    public void readActiveQueue(String message) {
        System.out.println("收到队列消息:" + message);
    }

    @JmsListener(destination = "${spring.activemq.topic-name}", containerFactory = "topicListener")
    public void readActiveTopic(String message) {
        System.out.println("收到主题消息:" + message);
    }

    /*
    如果想要【多个消费者】进行消费则注解为:
    @JmsListener(destination="${spring.activemq.queue-name}", containerFactory="queueListener",concurrency="3")
     */
}

测试一下

 

 

 

...全文
74 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

13,655

社区成员

发帖
与我相关
我的任务
社区描述
CSDN 下载资源悬赏专区
其他 技术论坛(原bbs)
社区管理员
  • 下载资源悬赏专区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧