SpringBoot整合ActiveMQ

1. 消息中间件产生的背景

在客户端与服务器进行通讯时.客户端调用后,必须等待服务对象完成处理返回结果才能继续执行。

客户与服务器对象的生命周期紧密耦合,客户进程和服务对象进程都都必须正常运行;如果由于服务对象崩溃或者网络故障导致用户的请求不可达,客户会受到异常。

2. 消息中间件概述

① 什么是消息中间件

面向消息的中间件(MessageOrlented MiddlewareMOM)较好的解决了以上问题。

发送者将消息发送给消息服务器,消息服务器将消感存放在若千队列中,在合适的时候再将消息转发给接收者。

这种模式下,发送和接收是异步的,发送者无需等待; 二者的生命周期未必相同: 发送消息的时候接收者不一定运行,接收的时候,发送者也不一定运行,一对多通信: 对于一个消息可以有多个接收者。

② 什么是JMS

JMS是java的消息服务,JMS的客户端之间可以通过JMS服务进行异步的消息传输。

JMS通讯模式:发布订阅和消息队列

发布订阅:一对多(消息模型),主题topic,如果消费者集群,每个消费者都会消费。

消息队列:点对点(消息模型),队列quque,如果消费者集群,均摊消息

③ 消息中间件的好处

流量削峰(秒杀系统),异步解耦

④ 目前常用mq对比

 ActiveMQRabbitMQRocketMQZeroMQ
关注度  
成熟度  成熟成熟比较成熟不成熟
所属社区/公司Apache Mozilla
Public
License
Alibaba   
社区活跃度  
文档  
特点  功能齐全,被大量开源项目使用由于Erlang 语言的并发能力,性能很好   各个环节分布式扩展设计,主从 HA;支持上万个队列;多种消费模式;性能很好低延时,高性能,最高 43万条消息每秒  
授权方式  开源开源开源开源
开发语言  JavaErlang  Java  C
支持的协议  OpenWire、
STOMP、
REST、XMPP、
AMQP
AMQP  自己定义的一
套(社区提供
JMS--不成熟)
TCP、UDP
客户端支持语言  Java、C、
C++、
Python、
PHP、
Perl、.net 等  
Java、C、
C++、
Python、 PHP、Perl 等
Java  
C++(不成熟)  
 
python、 java、 php、.net 等
持久化  内存、文件、数据库内存、文件磁盘文件在消息发送端保存
事务  支持不支持支持不支持
集群  支持支持支持不支持
负载均衡支持支持支持不支持
管理界面  一般无社区有 web
console   实现
部署方式  独立、嵌入独立独立独立
评价  优点:
   成熟的产品,已经在很多公司得到应用(非大规模场景)。有较多的文档。各种协议支持较好,有多重语言的成熟的客户端;
缺点:
根据其他用户反馈,会出莫名其妙的问题,切会丢失消息。 其重心放到activemq6.0 产品—apollo 上去了,目前社区不活跃,且对 5.x 维护较少;
Activemq 不适合用于上千个队列的应用场景
优点:   由于erlang语言的特性,mq 性能较好;管理界面较丰富,在互联网公司也有较大规模的应用;支持amqp系诶,有多中语言且支持 amqp 的客户端可用
 
缺点:
  erlang语言难度较
大。集群不支持动态扩展。
优点:
   模型简单,接口易用(JMS   的接口很多场合并不太实用)。在阿里大规模应用。目前支付宝中的余额宝等新兴产
品均使用rocketmq。集群规模大概在50 台左右,单日处理消息上百亿;性能非常好,可以大量堆
积消息在broker   中;支持多种消费,包括集群消费、广播消费等。开发度较活跃,版本更新很快。
 缺点:
 没有在 mq 核心中去实现JMS 等接口
 

3. SpringBoot整合ActiveMQ

① maven依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.4.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>activemqdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>ActiveMqDemo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

② application.yml配置

server:
  port: 8080
spring:
  activemq:
    broker-url: tcp://127.0.0.1:61616
    user: admin
    password: admin
queue: springboot-activemq-queue

③ 编写生产者代码

  ActiveMqProducer.java

package com.example.producer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Component;
import javax.jms.Destination;

@Component
public class ActiveMqProducer {

    // 也可以注入JmsTemplate,JmsMessagingTemplate对JmsTemplate进行了封装
    // JmsMessagingTemplate底层默认集成了持久化,用JmsTemplate的话需要写如下代码:
    //      jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT);

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

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

}

ActiveMqController.java

package com.example.controller;

import com.example.producer.ActiveMqProducer;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.jms.Destination;
import java.util.HashMap;
import java.util.Map;

@RestController
public class ActiveMqController {

    @Autowired
    private ActiveMqProducer activeMqProducer;

    @Value("${queue}")
    private String queue;

    /**
     * 生产者发送消息
     * @return
     */
    @GetMapping("/sendMessage")
    public String sendMessage(){
        Map<String,String> map = new HashMap<>();
        map.put("id","1");
        map.put("name","zhangsan");
        map.put("phone","123456");
        Destination destination = new ActiveMQQueue("queue");
        activeMqProducer.sendMessage(destination,map.toString());
        return "消息发送成功";
    }
}

此时启动ActiveMQ服务端,可以看到多了一个队列,并且为未消费状态。

此时,重启服务端,会发现之前的队列消息还在,即默认做了持久化。

④ 编写消费者代码

  ActiveMqConsumer.java

package com.example.consumer;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Component
public class ActiveMqConsumer {

    @Value("${queue}")
    private String queue;

    @JmsListener(destination = "queue")
    public void receiveQueue(String message) {
        System.out.println("消费端监听到消息:" + message);
    }
}

  启动消费端(这里我为了测试分了两个项目,实际开发中肯定在一个项目中),会发现消息已经被消费成功。

4. Topic模式消息的接收

由于ActiveMQ默认只支持Queue模式,所以要想订阅Topic模式需要手动开启发布订阅域(PubSubDomain)。

注意开启PubSubDomain后将无法接收Queue模式的消息,所以我们需要对Topic的接收者进行单独的配置.

Topic的消息订阅模式分为以下两种:非持久订阅和持久订阅

① 配置:以下是持久订阅,非持久订阅只需将factory.setSubscriptionDurable(true)去掉或者改为false即可

@Bean
public JmsListenerContainerFactory topicListenerFactory(ConnectionFactory connectionFactory){
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        // pubSubDomain 表示开启发布订阅域
        factory.setPubSubDomain(true);
        // 开启持久订阅。即下线后重新上线依然能继续接收Topic消息
        factory.setSubscriptionDurable(true);
        // 持久订阅的Client端标识(多个端持久订阅需要保证唯一性,否则可能会出现问题)
        factory.setClientId("test_client1");
        factory.setConnectionFactory(connectionFactory);
        return factory;
}

② 使用:(只需要在监听器加入一个属性containerFactory)

@JmsListener(destination = "linebus.publish.status.topic",containerFactory = "topicListenerFactory")
    public void receiveLinebusPublishStatusTopic(String message){
        try {
            Map<String, Object> map = JsonUtil.fromJson(message,Map.class);
            boolean status = (boolean) map.get("publishStatus");
            if(status){
                LOGGER.info("网站更新,业务暂停");
            }else{
                LOGGER.info("可以正常访问");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

挺简单的一个demo,做一个笔记,希望也对有需要的人提供到帮助!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值