activemq 的p2p和Publish/Subscribe 兩種模式

springboot 整合 activemq

  • 這個demo純粹是一個小demo 因爲爲了學習dubbo,在這個demo是實現了發佈訂閱和點對點兩種模式
    別的不多說,直接上代碼: 結尾我會把代碼貼上去
首先引入依賴
        <!-- 整合消息隊列ActiveMQ -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-activemq</artifactId>
        </dependency>
        <!-- 配置線程池 -->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-pool</artifactId>
        </dependency>
SpringBoot+ActiveMQ實戰之點對點模式(p2p)
 activemq:
    broker-url: tcp://127.0.0.1:61616  #地址
    user: admin
    password: admin
    pool:
      enabled: true
      max-connections: 100  #線程池
啓動類添加@EnableJms註解,開啓支持jms

在這裏插入圖片描述

  • 在springboot啓動類添加一個 queue對象,並交給spring進行管理
    @Bean
    public Queue queue() {
        return new ActiveMQQueue("message.queue");
    }

- 定義消息的生產者和消費者

import com.itcorey.service.ProducerService;
import org.apache.activemq.command.ActiveMQQueue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @Classname MessageController
 * @Description 定義消息的生產者和消費者
 * @Date 2020/5/19 14:44
 * @Created by corey
 */
@RestController
@RequestMapping("/api/message")
public class MessageController {
    @Resource
    private ProducerService producerService;
    @GetMapping("/send")
    public String sendMsg(String message) {
        new Thread(new Runnable() {
            @Override
            public void run() {
            for (int i = 0;i<=10;i++){
                // 目的地
                ActiveMQQueue desination = new ActiveMQQueue("message.queue");
                // 發送消息
                producerService.sendMessage(message, desination);
            }
            }
        }).start();
        return "success!!";
    }
}

- ProducerService.java

package com.itcorey.service;
import javax.jms.Destination;

/**
 * @Classname ProducerService
 * @Description 消息生產者
 * @Date 2020/5/19 14:47
 * @Created by corey
 */
public interface ProducerService {

    void sendMessage(final String msg);

    void sendMessage(final String msg, Destination destination);

    void publish(final String msg);
}

ProducerServiceImpl.java

@Service
public class ProducerServiceImpl implements ProducerService {
  @Autowired
  private Queue queue;// 默認消息隊列
  @Autowired
  private JmsMessagingTemplate JmsTemplate; // 用來發送消息到broker的對象

  //發送消息
  @Override
  public void sendMessage(String msg) {
    JmsTemplate.convertAndSend(this.queue, msg);
  }

  //發送消息
  @Override
  public void sendMessage(String msg, Destination destination) {
    JmsTemplate.convertAndSend(destination, msg);
  }
}

MessageConsumer.java:

@Component
public class MessageConsumer {
  @JmsListener(destination = "message.queue")
  public void receiveMessage(String txt) {
    System.out.println("MessageConsumer接收到的信息:" + txt);
  }
}

模擬請求
請求地址:http://localhost:8080/api/message/send?message=hello
在這裏插入圖片描述

結果

在這裏插入圖片描述
二、SpringBoot+ActiveMQ實戰之發佈訂閱模式(pub/sub)
需要加入配置文件,支持發佈訂閱模型,默認只支持點對點
#default point to point
spring.jms.pub-sub-domain=true
在這裏插入圖片描述
添加topic對象

@EnableJms
@SpringBootApplication
public class ActivemqWebApplication {
  @Bean
  public Topic topic() {
    return new ActiveMQTopic("news.topic");
  }

  @Bean
  ConnectionFactory connectionFactory() {
    return new ActiveMQConnectionFactory();
  }

  @Bean
  JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
    JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
    jmsTemplate.setPriority(999);
    return jmsTemplate;
  }

  @Bean(value = "jmsMessagingTemplate")
  JmsMessagingTemplate jmsMessagingTemplate(JmsTemplate jmsTemplate) {
    JmsMessagingTemplate messagingTemplate = new JmsMessagingTemplate(jmsTemplate);
    return messagingTemplate;
  }

  public static void main(String[] args) {
    SpringApplication.run(ActivemqWebApplication.class, args);
  }
}

定義消息的發佈者和訂閱者
NewsController.java

package com.itcorey.controller;

import com.itcorey.service.ProducerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * @Classname NewsController
 * @Description TODO
 * @Date 2020/5/19 15:47
 * @Created by corey
 */
@RequestMapping("/api/news")
@RestController
public class NewsController {
    @Autowired
    private ProducerService producerService;
    @GetMapping("/publish")
    public String publish(String news) {
        // 發佈信息
        producerService.publish(news);
        return "success!!!";
    }
}

ProducerService
在這裏插入圖片描述
ProducerServiceImpl實現

@Service
public class ProducerServiceImpl implements ProducerService {
  private Topic topic; // 默認主題
  @Autowired
  private JmsMessagingTemplate JmsTemplate; // 用來發送消息到broker的對象

  /**
   * 功能描述:發佈消息
   */
  @Override
  public void publish(String msg) {
    JmsTemplate.convertAndSend(this.topic, msg);
  }
}

NewsSub.java

@Component
public class NewsSub {
  @JmsListener(destination = "news.topic")
  public void receive1(String text) {
    System.out.println("news.topic 消費者:receive1=" + text);
  }

  @JmsListener(destination = "news.topic")
  public void receive2(String text) {
    System.out.println("news.topic 消費者:receive2=" + text);
  }

  @JmsListener(destination = "news.topic")
  public void receive3(String text) {
    System.out.println("news.topic 消費者:receive3=" + text);
  }
}

模擬測試
請求地址:http://localhost:8080/api/news/publish?news=topic
在這裏插入圖片描述
注意,如果相同時兼容兩種情況,P2P和pub/sub兩種.
@JmsListener如果不指定獨立的containerFactory的話是隻能消費queue消息,需要修改訂閱者container:containerFactory=“jmsListenerContainerTopic”

@Component
public class NewsSub {
  @JmsListener(destination = "news.topic", containerFactory = "jmsListenerContainerTopic")
  public void receive1(String text) {
    System.out.println("news.topic 消費者:receive1=" + text);
  }

  @JmsListener(destination = "news.topic", containerFactory = "jmsListenerContainerTopic")
  public void receive2(String text) {
    System.out.println("news.topic 消費者:receive2=" + text);
  }

  @JmsListener(destination = "news.topic", containerFactory = "jmsListenerContainerTopic")
  public void receive3(String text) {
    System.out.println("news.topic 消費者:receive3=" + text);
  }
}

需要在啓動類給topic定義獨立的JmsListenerContainer

@Bean
public JmsListenerContainerFactory<?> jmsListenerContainerTopic(ConnectionFactory activeMQConnectionFactory) {
    DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
    bean.setPubSubDomain(true);
    bean.setConnectionFactory(activeMQConnectionFactory);
    
    return bean;
}

在配置文件裏面,註釋掉 #spring.jms.pub-sub-domain=true

寫在最後:

1.什麼是JMS
JMS是java消息服務(java Message service) 應用接口,是一個java平臺中關於面向消息中間件(MOM)的API,用於兩個程序之間,或分佈式系統中發送消息進行異步通信.Java消息服務是一個與具體平臺無關的API,絕大多數MOM提供商都對JMS提供支持(百度百科給出的概述)。我們可以簡單的理解:兩個應用程序之間需要進行通信,我們使用一個JMS服務,進行中間的轉發,通過JMS 的使用,我們可以解除兩個程序之間的耦合。

2. JMS的優勢

  1. Asynchronous(異步)
    JMS 原本就是一個異步的消息服務,客戶端獲取消息的時候,不需要主動發送請求,消息會自動發送給可用的客戶端。
    2. Reliable(可靠)
    JMS保證消息只會遞送一次。大家都遇到過重複創建消息問題,而JMS能幫你避免該問題。
    3 JMS的消息模式
    點對點通信模型(Point-to-Point)在點對點通信模式中,應用程序由消息隊列,發送方,接收方組成。每個消息都被髮送到一個特定的隊列,接收者從隊列中獲取消息。隊列保留着消息,直到他們被消費或超時。
    在這裏插入圖片描述
    特點:
  • 每個消息只要一個消費者
  • 發送者接受者在時間上沒有時間約束,也就是說發送者在發送完消息之後,不管接收者有沒有接受消息,都不會影響發送方發送消息到消息隊列中。
  • 發送方不管是否在發送消息,接收方都可以從消息隊列中取到消息,(The receiver can fetch message whether it is running or not when the sender sends the message)。
  • 接收方在接收完消息之後,需要向消息隊列應答成功。
  1. 發佈/訂閱通信模型(Publish/Subscribe Messaging Domain)
    在發佈/訂閱消息模型中,發佈者發佈一個消息,該消息通過topic傳遞給所有的客戶端,該模式下,發佈者與訂閱者都是匿名的,即發佈者與訂閱者都不知道對方是誰。並且可以動態的發佈與訂閱Topic。Topic主要用於保存和傳遞消息,且會一直保存消息直到消息被傳遞給客戶端。
    在這裏插入圖片描述
    特點
  • 一個消息可以傳遞個多個訂閱者(即:一個消息可以有多個接受方)。
  • 發佈者與訂閱者具有時間約束,針對某個主題(Topic)的訂閱者,它必須創建一個訂閱者之後,才能消費發佈者的消息,而且爲了消費消息,訂閱者必須保持運行的狀態。
  • 爲了緩和這樣嚴格的時間相關性,JMS允許訂閱者創建一個可持久化的訂閱。這樣,即使訂閱者沒有被激活(運行),它也能接收到發佈者的消息。
JMS的編程模型
  1. ConnectionFactory:連接工廠,JMS用它創建連接
  2. Connnection:連接對象,JMS Client到JMS Provider的連接
  3. Destination:消息目的地,由Session創建
  4. Session:會話,由Connection創建,實質上就是發送、接受消息的一個線程,因此生產者、消費者都是Session創建的
  5. Provider/MessageProvider:消息生產者
  6. Consumer/MessageConsumer:消息消費者
  7. Message Listeners:消息監聽者
    在這裏插入圖片描述
    源碼地址:https://github.com/coreyxuy/springboot-email.git
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章