一篇学会Spring Boot集成消息队列ActiveMQ

Spring Boot中集成ActiveMQ

JMS和ActiveMQ的概念
  • JMS即java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。
  • JMS只是接口,不同的供应商和开源组织对其有不同的实现,ActiveMQ就是其中之一,它支持JMS,是Apache推出的。
  • JMS中存在多个对象模型:
    • 连接工厂:ConnectionFactory
    • JMS连接:Connect
    • JMS会话:Session
    • JMS目的:Destination
    • JMS生产者:Producer
    • JMS消费者:Consumer
    • JMS消息两种类型:点对点和发布/订阅
  • 可以看出 JMS 实际上和 JDBC 有点类似,JDBC 是可以⽤来访问许多不同关系数据库的 API,⽽ JMS 则提供同样与⼚商⽆关的访问⽅
    法,以访问消息收发服务。
  • ActiveMQ是Apache的一个开源消息总线,ActiveMQ 完全⽀持JMS1.1和J2EE 1.4规范,尽管 JMS 规范出台已经是很久
    的事情了,但是 JMS 在当今的 Java EE 应⽤中间仍然扮演着特殊的地位。ActiveMQ ⽤在异步消息的处理上,所谓异步消息即消息发送者
    ⽆需等待消息接收者的处理以及返回,甚⾄⽆需关⼼消息是否发送成功。
  • 异步消息主要有两种⽬的地形式,队列(queue)和主题(topic),队列⽤于点对点形式的消息通信,主题⽤于发布/订阅式的消息通信。
ActiveMQ的下载和安装
  • 下载地址:https://activemq.apache.org/components/classic/download/

    • 注意:jdk8最高只支持5.15.x,下载更高版本的需要对应的jdk环境
    • 下载可以参考其他的安装教程,网上一搜一大把
    • 安装成功之后访问ActiveMQ网址:http://localhost:8161/admin/
    • 初始账号密码都是admin,登陆进去之后就说明安装成功了。
      在这里插入图片描述
  • 页面存在Queues 和 Topics 这两个选项,这两个选项分别是点对点消息和发布/订阅消息的查看窗⼝。

    • 点对点消息:消息⽣产者⽣产消息发布到 queue 中,然后消息消费者从 queue 中取出,并且消费消息。这⾥需要注意:消息被消费者消费
      以后,queue 中不再有存储,所以消息消费者不可消费到已经被消费的消息。Queue ⽀持存在多个消息消费者,但是对⼀个消息⽽⾔,只
      会有⼀个消费者可以消费。
    • 发布/订阅消息:消息⽣产者(发布)将消息发布到 topic 中,同时有多个消息消费者(订阅)消费该消息。和点对点⽅式不同,发布到
      topic 的消息会被所有订阅者消费。下⾯分析具体的实现⽅式。
集成ActiveMQ
依赖导入与配置
  • 依赖导入
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
  • 配置
    • 在application.yml文件中增加ActiveMQ的配置
spring:
 activemq:
 # activemq url
 broker-url: tcp://localhost:61616
 in-memory: true
 pool:
 # 如果此处设置为true,需要添加activemq-pool的依赖包,否则会⾃动配置失败,⽆法注⼊JmsMessagingTemplate
 enabled: false
Queue 和 Topic 创建
  • 创建两种消息 Queue 和 Topic,这两种消息的创建,我们放到 ActiveMqConfig 中来创建
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.jms.Destination;
/**
 * @author liujf
 */
@Configuration
public class ActiveMqConfig {
    public static final String TOPIC_NAME = "activemq.topic";
    public static final String QUEUE_NAME = "activemq.queue";

    @Bean
    public Destination topic() {
        return new ActiveMQTopic(TOPIC_NAME);
    }
    @Bean
    public Destination queue() {
        return new ActiveMQQueue(QUEUE_NAME);
    }
}
  • 可以看出创建 Queue 和 Topic 两种消息,分别使⽤ new ActiveMQQueue 和 new ActiveMQTopic 来创建,分别跟上对应消息的名称即
    可。这样在其他地⽅就可以直接将这两种消息作为组件注⼊进来了。
发送消息
  • 在 Spring Boot 中,我们只要注⼊ JmsMessagingTemplate 模板即可快速发送消息
@Service
public class MsgProducer {
    @Resource
    private JmsMessagingTemplate jmsMessagingTemplate;

    public void sendMessage(Destination destination, String msg){
        jmsMessagingTemplate.convertAndSend(destination.getName(), msg);
    }
}
  • convertAndSend ⽅法中第⼀个参数是消息发送的⽬的地,第⼆个参数是具体的消息内容。
点对点消息生产与消费
  • 消息的生产一般在Controller中,由于上面生成了Queue消息的组件,所以在Controller中我们直接注入就可以,然后调用上文的消息发送方法sendMessage就可以生产一条消息了。
@RestController
@RequestMapping("/activemq")
public class ActiveMqController {
    private static final Logger logger = LoggerFactory.getLogger(ActiveMqController.class);
    @Resource
    private MsgProducer msgProducer;
    @Resource
    private Destination queue;
    @GetMapping("/send/queue")
    public String sendQueueMessage(){
        logger.info("开始发送点对点的消息-------------");
        msgProducer.sendMessage(queue,"queue:hello activemq!");
        return "success";
    }
}
  • 消息的消费很简单,我们只需指定目的地就可以了,jms监听器一直在监听是否有消息过来,如果有则消费。
@Service
public class QueueConsumer {
    @JmsListener(destination = ActiveMqConfig.QUEUE_NAME)
    public void receiveQueueMsg(String msg){
        System.out.println("收到消息"+msg);
    }
}
  • 消费者只需要定义业务类就行了,不需要主动的去消费,当监听到有消息后就会自动的消费。
  • 访问:http://localhost:8001/activemq/send/queue
    • 控制台打印:=开始发送点对点消息=
    • 收到消息Queue: hello activemq!
发布/订阅消息的生产和消费
  • 消息的生产和点对点的形式一样,我们注入Topic并调用producer的sendMessage方法即可发送订阅消息
  • 定义生产逻辑
@Service
public class MsgProducer {
    @Resource
    private JmsMessagingTemplate jmsMessagingTemplate;

    public void sendMessage(Destination destination, String msg){
        jmsMessagingTemplate.convertAndSend(destination, msg);
    }
}
  • controller中进行测试
@RestController
@RequestMapping("/activemq")
public class ActiveTopicController {
    private static final Logger logger = LoggerFactory.getLogger(ActiveMqController.class);
    @Resource
    private MsgProducer producer;
    @Resource
    private Destination topic;
    @GetMapping("/send/topic")
    public String sendTopicMessage() {
        logger.info("===开始发送订阅消息===");
        producer.sendMessage(topic, "Topic: hello activemq!");
        return "success";
    }
}
  • 发布/订阅消息的消息和点对点不同,订阅消息支持多个消费者一起消费。其次,SpringBoot中默认的点对点消息,所以在使用Topic时会不起作用。
  • 我们需要在配置⽂件 application.yml 中添加⼀个配置:
spring:
 jms:
  pub-sub-domain: true
  • 该配置是 false 的话,则为点对点消息,也是 Spring Boot 默认的。这样是可以解决问题,但是如果这样配置的话,上⾯提到的点对点消
    息⼜不能正常消费了。所以⼆者不可兼得,这并⾮⼀个好的解决办法。
  • ⽐较好的解决办法是,我们定义⼀个⼯⼚,@JmsListener 注解默认只接收 queue 消息,如果要接收 topic 消息,需要设置⼀下
    containerFactory。我们还在上⾯的那个 ActiveMqConfig 配置类中添加:
@Configuration
public class ActiveMqConfig {
    public static final String TOPIC_NAME = "activemq.topic";
    public static final String QUEUE_NAME = "activemq.queue";
    @Bean
    public Destination topic() {
        return new ActiveMQTopic(TOPIC_NAME);
    }
    @Bean
    public Destination queue() {
        return new ActiveMQQueue(QUEUE_NAME);
    }
    /**
     * JmsListener注解默认只接收queue消息,如果要接收topic消息,需要设置containerFactory
     */
    @Bean
    public JmsListenerContainerFactory topicListenerContainer(ConnectionFactory connectionFactory) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        // 相当于在application.yml中配置:spring.jms.pub-sub-domain=true
        factory.setPubSubDomain(true);
        return factory;
    }
}
  • 经过这样的配置之后,我们在消费的时候,在 @JmsListener 注解中指定这个容器⼯⼚即可消费 topic 消息。
  • 定义多个消费者业务类:
@Service
public class TopicConsumer {
    /**
     * 接收订阅消息
     * @param msg
     */
    @JmsListener(destination = ActiveMqConfig.TOPIC_NAME, containerFactory = "topicListenerContainer")
    public void receiveTopicMsg(String msg) {
        System.out.println("消费者1号收到的消息为:" + msg);
    }
}
@Service
public class TopicConsumer2 {
  /**
   * 接收订阅消息
   * @param msg
   */
  @JmsListener(destination = ActiveMqConfig.TOPIC_NAME, containerFactory = "topicListenerContainer")
  public void receiveTopicMsg(String msg) {
    System.out.println("消费者2号收到的消息为:" + msg);
  }
}
  • 访问:http://localhost:8001/activemq/send/topic
    • 控制台打印:
      • =开始发送订阅消息=
      • 消费者2号收到的消息为:Topic: hello activemq!
      • 消费者1号收到的消息为:Topic: hello activemq!
  • 27
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值