消息队列(RabbitMQ和ActiveMQ)

1、服务安装
(1)RabbitMQ Docker安装
查询
docker search rabbitmq
下载镜像
选择的是可以访问web管理界面的tag
docker pull rabbitmq:management
创建容器
docker run -dit --name Myrabbitmq -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=123456 -p 15678:15672 -p 5678:5672 rabbitmq:management

备注:15672是管理界面的端口,5672是服务的端口。这里顺便将管理系统的用户名和密码设置为admin admin

RabbitMQ 下载地址
Erlang 下载地址

(2)ActiveMQ Docker安装
查询
docker search activemq
下载镜像
docker pull webcenter/activemq
查看镜像
docker image
创建容器
docker run -d --name activemq -p 61617:61616 -p 8162:8161 webcenter/activemq

  • 61616是 activemq 的容器使用端口(映射为61617)
  • 8161是 web 页面管理端口(对外映射为8162)

默认用户名和密码:admin/admin

修改用户名和密码
使用 docker exec -it activemq /bin/bash 进入 ActiveMQ

1.搜索文件,并找到
find / -name ‘jetty-realm.properties’
2,修改配置文件
vi jetty-realm.properties
3,修改重启服务
在这里插入图片描述

2、RabbitMQ使用
(1)消息提供端
POM依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

配置

spring:  
  rabbitmq:
    # rabbitmq安装位置
    host: 192.168.1.225
    # rabbitmq的端口
    port: 5678
    # rabbitmq的用户名
    username: admin
    # rabbitmq的用户密码
    password: 123456
    # 配置虚拟机
    virtual-host: /
    # 开启消息确认机制 confirm 异步
    publisher-confirm-type: correlated
#    publisher-confirms: true # 之前的旧版本 开启消息确认机制的方式
    # 开启return机制
    publisher-returns: true
    # 消息开启手动确认
    listener:
      direct:
        acknowledge-mode: manual

创建 RabbitmqConfig

@SpringBootConfiguration
public class RabbitmqConfig {
/****************************Work 模型******************************************/
    /**
     * 配置一个工作模型队列
     * work模型
     * @return
     */
    @Bean
    public Queue queueWork1() {
        return new Queue("queue_work");
    }
/****************************Work 模型******************************************/
/****************************发布订阅模式******************************************/
    /**
     * 声明两个队列
     * @return
     */
    @Bean
    public Queue queueFanout1() {
        return new Queue("queue_fanout1");
    }
    @Bean
    public Queue queueFanout2() {
        return new Queue("queue_fanout2");
    }
    /**
     * 准备一个交换机
     * @return
     */
    @Bean
    public FanoutExchange exchangeFanout() {
        return new FanoutExchange("exchange_fanout");
    }
    /**
     * 将交换机和队列进行绑定
     * @return
     */
    @Bean
    public Binding bindingExchange1() {
        return BindingBuilder.bind(queueFanout1()).to(exchangeFanout());
    }
    @Bean
    public Binding bindingExchange2() {
        return BindingBuilder.bind(queueFanout2()).to(exchangeFanout());
    }
/****************************发布订阅模式******************************************/
/****************************Topic 模型******************************************/
    @Bean
    public Queue queueTopic1() {
        return new Queue("queue_topic1");
    }
    @Bean
    public Queue queueTopic2() {
        return new Queue("queue_topic2");
    }
    @Bean
    public TopicExchange exchangeTopic() {
        return new TopicExchange("exchange_topic");
    }
    @Bean
    public Binding bindingTopic1() {
        return BindingBuilder.bind(queueTopic1()).to(exchangeTopic()).with("topic.#");
    }
    @Bean
    public Binding bindingTopic2() {
        return BindingBuilder.bind(queueTopic2()).to(exchangeTopic()).with("topic.*");
    }
/****************************Topic 模型******************************************/
/****************************confirm机制******************************************/
    /**
     * confirm 机制,创建一个队列
     * @return
     */
    @Bean
    public Queue queueConfirm() {
        return new Queue("queue_confirm");
    }
/****************************confirm机制******************************************/
/****************************return机制******************************************/
    @Bean
    public Queue queueReturn() {
        return new Queue("queue_return");
    }
    @Bean
    public TopicExchange exchangeReturn() {
        return new TopicExchange("exchange_return");
    }
    @Bean
    public Binding bindingReturn() {
        return BindingBuilder.bind(queueReturn()).to(exchangeReturn()).with("return.*");
    }
/****************************return机制******************************************/
/****************************TTL队列、死信队列******************************************/
    /**
     * TTL 队列
     * @return
     */
    @Bean
    public Queue queueTTL() {
        Map<String, Object> map = new HashMap<>(1);
        map.put("x-message-ttl", 10000);
        return new Queue("queue_ttl", true, false, false, map);
    }
    /**
     * 死信队列
     * @return
     */
    @Bean
    public Queue queueDLX() {
        Map<String, Object> map = new HashMap<>(2);
        // 5秒后,消息自动变为死信
        map.put("x-message-ttl", 5000);
        map.put("x-dead-letter-exchange", "exchange_receive");
        map.put("x-dead-letter-routing-key", "receive_key");
        return new Queue("queue_dlx", true, false, false, map);
    }
    /**
     * 死信交换机
     * @return
     */
    @Bean
    public DirectExchange exchangeDLX() {
        return new DirectExchange("exchange_dlx");
    }
    /**
     * 死信队列绑定交换机
     * @return
     */
    @Bean
    public Binding bindingDLX() {
        return BindingBuilder.bind(queueDLX()).to(exchangeDLX()).with("receive_key");
    }
    /**
     * 死信接收交换机
     * @return
     */
    @Bean
    public DirectExchange exchangeReceive() {
        return new DirectExchange("exchange_receive");
    }
    /**
     * 接收死信的队列
     * @return
     */
    @Bean
    public Queue queueReceive() {
        return new Queue("queue_receive");
    }
    /**
     * 交换机与队列绑定
     * @return
     */
    @Bean
    public Binding bindingReceive() {
        return BindingBuilder.bind(queueReceive()).to(exchangeReceive()).with("receive_key");
    }
/****************************TTL队列、死信队列******************************************/
}

创建 Sender

@Component
public class Sender {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * work模型
     * 一个发送,多个轮着接收
     * @param msg
     */
    public void sendWork(String msg){
        /**
         * 参数一:路由键
         * 参数二:发送的消息
         */
        this.rabbitTemplate.convertAndSend("queue_work", msg);
    }
    /**
     * 向发布订阅模式里面发送消息
     * 一个发送,多个同时接收
     * @param msg
     */
    public void sendPublish(String msg) {
        /**
         * 参数一:交换器名称
         * 参数二:路由键
         * 参数三:发送的消息
         */
        rabbitTemplate.convertAndSend("exchange_fanout", "", msg);
    }
    /**
     * 向topic模型发送数据
     * 一个发送,多个同时接收(根据路由键)
     * 消费者1 接收到了所有的数据
     * 消费者2只接受到了一半(奇数)的数据
     * @param msg
     * @param id
     */
    public void sendTopic(String msg,Integer id) {
        if (id % 2 == 0) {
            rabbitTemplate.convertSendAndReceive("exchange_topic", "topic.km.topic", msg + id);
        } else {
            rabbitTemplate.convertSendAndReceive("exchange_topic", "topic.km", msg + id);
        }
    }
    /**
     * confirm机制
     * 提供端和消费端的Msg包路径必须保持一致
     * @param id
     */
    public void sendConfirm(Integer id) {
        rabbitTemplate.convertAndSend("queue_confirm", new Msg(id, "km", "km123"), new CorrelationData("" + System.currentTimeMillis()));
        rabbitTemplate.setConfirmCallback(confirmCallback);
    }
    /**
     * 配置 confirm 机制
     */
    private final RabbitTemplate.ConfirmCallback confirmCallback = new RabbitTemplate.ConfirmCallback() {
        /**
         * @param correlationData 消息相关的数据,一般用于获取 唯一标识 id
         * @param b true 消息确认成功,false 失败
         * @param s 确认失败的原因
         */
        @Override
        public void confirm(CorrelationData correlationData, boolean b, String s) {
            if (b) {
                System.out.println("confirm 消息确认成功..." + correlationData.getId());
            } else {
                System.out.println("confirm 消息确认失败..." + correlationData.getId() + " cause: " + s);
            }
        }
    };
    /**
     * return机制
     * 找不到路由则会返回消息
     * @param msg
     * @param id
     */
    public void sendReturn(String msg,Integer id) {
        if (id % 2 == 0) {
            rabbitTemplate.convertAndSend("exchange_return", "return.km.km", msg + id);
        } else {
            rabbitTemplate.convertAndSend("exchange_return", "return.km", msg + id);
        }
        rabbitTemplate.setReturnCallback(returnCallback);
    }
    /**
     * 配置 return 消息机制
     */
    private final RabbitTemplate.ReturnCallback returnCallback = new RabbitTemplate.ReturnCallback() {
        /**
         *  return 的回调方法(找不到路由才会触发)
         * @param message 消息的相关信息
         * @param i 错误状态码
         * @param s 错误状态码对应的文本信息
         * @param s1 交换机的名字
         * @param s2 路由的key
         */
        @Override
        public void returnedMessage(Message message, int i, String s, String s1, String s2) {
            System.out.println(message);
            System.out.println(new String(message.getBody()));
            System.out.println(i);
            System.out.println(s);
            System.out.println(s1);
            System.out.println(s2);
        }
    };
}

(2)消息消费端
POM依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

配置

spring:  
  rabbitmq:
    # rabbitmq安装位置
    host: 192.168.1.225
    # rabbitmq的端口
    port: 5678
    # rabbitmq的用户名
    username: admin
    # rabbitmq的用户密码
    password: 123456
    # 配置虚拟机
    virtual-host: /
    # 开启消息确认机制 confirm 异步
    publisher-confirm-type: correlated
#    publisher-confirms: true # 之前的旧版本 开启消息确认机制的方式
    # 开启return机制
    publisher-returns: true
    # 消息开启手动确认
    listener:
      direct:
        acknowledge-mode: manual

消息监听

@Component
public class ReceiveListener {
/****************************Work 模型******************************************/
/**
 * work模型
 * 一个发送,多个轮着接收
 */
    @RabbitListener(queues = "queue_work")
    public void receiveMessage(String msg, Channel channel, Message message) {
        // 只包含发送的消息
        System.out.println("1接收到消息:" + msg);
        // channel 通道信息
        // message 附加的参数信息
    }
    @RabbitListener(queues = "queue_work")
    public void receiveMessage2(Object obj, Channel channel, Message message) {
        // 包含所有的信息
        System.out.println("2接收到消息:" + obj);
    }
/****************************Work 模型******************************************/
/****************************发布订阅模式******************************************/
/**
 * 向发布订阅模式里面发送消息
 * 一个发送,多个同时接收
 */
     @RabbitListener(queues = "queue_fanout1")
    public void receiveMsg1(String msg) {
        System.out.println("队列1接收到消息:" + msg);
    }
    @RabbitListener(queues = "queue_fanout2")
    public void receiveMsg2(String msg) {
        System.out.println("队列2接收到消息:" + msg);
    }
/****************************发布订阅模式******************************************/
/****************************Topic 模型******************************************/
/**
 * 向topic模型发送数据
 * 一个发送,多个同时接收(根据路由键)
 * 消费者1 接收到了所有的数据
 * 消费者2只接受到了一半(奇数)的数据
 */
     @RabbitListener(queues = "queue_topic1")
    public void receiveMsg1(String msg) {
        System.out.println("消费者1接收到:" + msg);
    }
    @RabbitListener(queues = "queue_topic2")
    public void receiveMsg2(String msg) {
        System.out.println("消费者2接收到:" + msg);
    }
/****************************Topic 模型******************************************/
/****************************confirm机制******************************************/
/**
 * confirm机制
 * 提供端和消费端的Msg包路径必须保持一致
 */
     @RabbitListener(queues = "queue_confirm")
    public void receiveMsg(Msg msg) {
        System.out.println("接收到的消息为:" + msg);
    }
/****************************confirm机制******************************************/
/****************************return机制******************************************/
/**
 * return机制
 * 找不到路由则会返回消息
 */
     @RabbitListener(queues = "queue_return")
    public void receiveMsg(String msg) {
        System.out.println("接收的消息为:" + msg);
    }
/****************************return机制******************************************/
}

3、ActiveMQ使用
(1)消息提供端
POM依赖

        <!-- ActiveMQ的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <dependency>
            <groupId>org.messaginghub</groupId>
            <artifactId>pooled-jms</artifactId>
        </dependency>
        <!--消息队列连接池-->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
        </dependency>

配置

  activemq:
    #activemq的url
    broker-url: tcp://192.168.1.225:61617
    #用户名
    user: admin
    #密码
    password: admin
    #是否使用线程池
    pool:
      #启用连接池
      enabled: true
      #连接池最大连接数
      max-connections: 5
      #空闲的连接过期时间,默认为30秒
      idle-timeout: 30s
    #是否信任所有包
    packages:
      trust-all: true
  #默认情况下,activemq使用的是queue模式,如果要使用topic模式,必须设置为true
  jms:
    pub-sub-domain: true

启动类添加注解 @EnableJms

@EnableJms
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class SeataOrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(SeataOrderApplication.class, args);
    }
}

创建Sender

@Component("Senders")
public class Sender {
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;
    /**
     * 将User对象转换成Message对象,并发送到queue或者topic
     *
     * @param msg
     * @return
     */
    public boolean produce(Msg msg) {
        Destination destination = new ActiveMQQueue("queue01");
        jmsMessagingTemplate.convertAndSend(destination, msg);
        return true;
    }
    /**
     * 延时发送的信息
     * @param msg 发送的数据
     * @param time 延时多少时间处理消息.
     */
    public void delaySend(String msg, long time) {
        //获取连接工厂
        ConnectionFactory connectionFactory = jmsMessagingTemplate.getConnectionFactory();
        try {
            //获取连接
            assert connectionFactory != null;
            Connection connection = connectionFactory.createConnection();
            connection.start();
            //获取session, true开启事务,false关闭事务
            Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
            // 创建一个消息队列
            Destination destination = session.createQueue("queue02");
            MessageProducer producer = session.createProducer(destination);
            producer.setDeliveryMode(DeliveryMode.PERSISTENT);
            TextMessage message = session.createTextMessage(msg);
            //设置延迟时间 //AMQ_SCHEDULED_DELAY
            message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time * 1000L);
            //发送
            producer.send(message);
            session.commit();
            producer.close();
            session.close();
            connection.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 将User对象转换成Message对象,并发送到queue或者topic
     *
     * @param msg
     * @return
     */
    public boolean produceTopic(Msg msg) {
        Destination destination = new ActiveMQTopic("topic01");
        jmsMessagingTemplate.convertAndSend(destination, msg);
        return true;
    }
}

(2)消息消费端
POM依赖

        <!-- ActiveMQ的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <dependency>
            <groupId>org.messaginghub</groupId>
            <artifactId>pooled-jms</artifactId>
        </dependency>
        <!--消息队列连接池-->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
        </dependency>

配置

  activemq:
    #activemq的url
    broker-url: tcp://192.168.1.225:61617
    #用户名
    user: admin
    #密码
    password: admin
    #是否使用线程池
    pool:
      #启用连接池
      enabled: true
      #连接池最大连接数
      max-connections: 5
      #空闲的连接过期时间,默认为30秒
      idle-timeout: 30s
    #是否信任所有包
    packages:
      trust-all: true
  #默认情况下,activemq使用的是queue模式,如果要使用topic模式,必须设置为true
  jms:
    pub-sub-domain: true

启动类添加注解 @EnableJms

@EnableJms
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class SeataBusinessApplication {
    public static void main(String[] args) {
        SpringApplication.run(SeataOrderApplication.class, args);
    }
}

消息监听

@EnableJms
@Component
public class ReceiveListener {
    @JmsListener(destination = "queue01", containerFactory = "queueContainerFactory")
    public void customer(Msg msg) {
        System.out.println("接收到的消息:");
        System.out.println(msg);
    }
    @JmsListener(destination = "queue02", containerFactory = "queueContainerFactory")
    public void customer2(String msg) {
        System.out.println("接收延时消息:" + msg);
    }
    @JmsListener(destination = "topic01", containerFactory = "topicContainerFactory")
    public void customer3(Msg msg) {
        System.out.println("收到订阅消息:" + msg);
    }
}

若要同时使用queue和topic,需添配置类,并在监听注解@JmsListener上添加containerFactory

@Configuration
public class ActivemqConfig {
    /**
     * 实现监听queue
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    public JmsListenerContainerFactory<?> queueContainerFactory(ConnectionFactory connectionFactory){
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setPubSubDomain(false);
//        factory.setTaskExecutor(pool);
        return factory;
    }
    /**
     * 实现监听topic
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    public JmsListenerContainerFactory<?> topicContainerFactory(ConnectionFactory connectionFactory){
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setPubSubDomain(true);
//        factory.setTaskExecutor(pool);
        return factory;
    }
}

示例

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值