gradle+springBoot2.2集合ActiveMq

我们在基于springBoot开发的时候,需要整合ActiveMq。

一:ActiveMq的下载和启动

          ActiveMq包的下载地址,本文用的是windows版的5.15.3版本,下载下来是压缩包,自行解压一个到目录下,CMD进入到解压目录下的bin目录下,执行 activemq.bat start 启动。                                                                            

   如果能成功访问http://localhost:8161/admin(用户名和密码默认为admin),则启动成功。
 

二:springBoot集成activeMQ

1:点对点

我们以springBoot2.2为例

首先需要准备两个项目,Provider和Consumer项目。

第一步:引入jar包。

compile('org.springframework.boot:spring-boot-starter-activemq')
compile group: 'org.messaginghub', name: 'pooled-jms', version: '1.1.0'

在这个地方一定要切记:

 不能再引入springBoot的时候,把geronimo的包去除了。因为ActiveMq需要这个包。下面的要注解掉。

config.exclude group: "org.apache.geronimo.specs"
config.exclude group: "com.google.code.findbugs"

还有一个问题,就是启动的时候出现,JmsMessagingTemplate无法注入的问题,这是因为:springBoot2.0以下使用的是:

使用springboot2.0+及以下版本时候,maven配置依赖是:

compile group: 'org.apache.activemq', name: 'activemq-pool', version: '5.15.0'

使用springboot2.1+时候,maven配置依赖是:
compile group: 'org.messaginghub', name: 'pooled-jms', version: '1.1.0'

第二步:在代码中引用mq

在Provider和Consumer的启动类里添加:

@EnableJms

1:在Provider中需要的jar包。

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-activemq')
    compile group: 'org.messaginghub', name: 'pooled-jms', version: '1.1.0'

}

准备一个BeanConfig定义消息队列

 

代码如下:

import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.jms.Queue;

/**
 * Created by zhm on 2020/5/6.
 */
@Configuration
public class BeanConfig {
    //定义存放消息的队列
    @Bean
    public Queue queue() {
        return new ActiveMQQueue("ActiveMQQueue");
    }

}

所以接下来在controller中准备

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.jms.Queue;

/**
 * Created by zhm on 2020/5/6.
 */
@RestController
public class ProviderController {
    //注入存放消息的队列,用于下列方法一
    @Autowired
    private Queue queue;

    //注入springboot封装的工具类
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @RequestMapping("send")
    public void send(String name) {
        //方法一:添加消息到消息队列
        jmsMessagingTemplate.convertAndSend(queue, name);
        //方法二:这种方式不需要手动创建queue,系统会自行创建名为test的队列
        //jmsMessagingTemplate.convertAndSend("test", name);
    }


}

启动provider,向消息队列添加数据,本次添加5条数据

http://localhost:8201/send?name=Tim

http://localhost:8201/send?name=Time

http://localhost:8201/send?name=Times

http://localhost:8201/send?name=Timess

 

启动consumer,控制台输出如下

成功接受NameTim
成功接受NameTime
成功接受NameTimes
成功接受NameTimess


ActiveMq持久化机制

 

2:广播方式

以上是点对点的方式。接下来就是广播的方式。

(1):这个时候需要在applicaton.properties中添加如下,开启广播。

spring.jms.pub-sub-domain=true

(2):接着准备ActiveMqConfig

import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.jms.Topic;

/**
 * Created by zhm on 2020/5/6.
 */
@Configuration
public class AcitvemqConfig {
    /**
     * 发布/订阅
     */
    @Bean
    public Topic topic() {
        return new ActiveMQTopic("active.topic");
    }
}

(3):在Provider中准备广播者SendController

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.jms.Topic;
import java.util.UUID;

/**
 * Created by zhm on 2020/5/6.
 */
@RestController
public class SendController {

    //注入主题
    @Autowired
    private Topic topic;

    //注入springboot封装的工具类
    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;
    /*
 * 发送 主题消息
 */
    @RequestMapping("/sendTopic")
    public String sendTopic() {
        String message = UUID.randomUUID().toString();
        // 指定消息发送的目的地及内容
        jmsMessagingTemplate.convertAndSend(this.topic, message);
        return "消息发送成功!message=" + message;
    }
}

 

接下来,在相应的consumer1和consumer2中添加如下代码

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

/**
 * Created by zhm on 2020/5/6.
 */
@Component
public class TopicCustomerController {
    /*
 * 监听和接收  主题消息1
 */
    @JmsListener(destination = "active.topic")
    public void readActiveTopic1(String message) {
        System.out.println("Customer1接受到:" + message);
    }

}

(3):广播这provider启动,然后 http://localhost:8201/sendTopic,执行多次,

这样在http://localhost:8161/admin/topics.jsp可以看到广播信息

(4):启动consumer1和consumer2,这样控制台就收到了:

Customer1接受到:e720d5ec-c748-448a-8ebd-f8a104ec7baa

 

三:面试问题。

(1):ActiveMQ消息发送失败

ActiveMQ有两种通信方式,点到点形式和发布订阅模式。
a:如果是点到点模式的话,如果消息发送不成功,此消息默认会保存到ActiveMQ服务端直到有消费者将其消费,所以此消息是不会丢失的。
b:如果是发布订阅模式的通信方式,默认情况只通知一次,如果接受不到此消息就没有了,这种场景使用于对消息发送率要求不高的情况,

c:如果要求消息必须送达不可以丢失的话,需要配置持久订阅。每个订阅端定义一个id,在订阅是向ActiveMQ注册,发布消息和接受消息时需要配置发送模式为持久化,此时如果客户端接受不到消息,消息会持久化到服务端,直到客户端正常接收后为止。

(2):如何防止消息重复发送

  • 解决方法:增加消息状态表。
  • 通俗来说就是一个账本,用来记录消息的处理状态,每次处理消息之前,都去状态表中查询一次,如果已经有相同的消息存在,那么不处理,可以防止重复发送。

(3):丢消息怎么办

  • 解决方案:用持久化消息【可以使用对数据进行持久化JDBC,AMQ(日志文件),KahaDB和LevelDB】,或者非持久化消息及时处理不要堆积,或者启动事务,启动事务后,commit()方法会负责任的等待服务器的返回,也就不会关闭连接导致消息丢失了。

(4):服务挂掉

这得从ActiveMQ的储存机制说起。在通常的情况下,非持久化消息是存储在内存中的,持久化消息是存储在文件中的,它们的最大限制在配置文件的<systemUsage>节点中配置。但是,在非持久化消息堆积到一定程度,内存告急的时候,ActiveMQ会将内存中的非持久化消息写入临时文件中,以腾出内存。虽然都保存到了文件里,但它和持久化消息的区别是,重启后持久化消息会从文件中恢复,非持久化的临时文件会直接删除
 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值