Spring Boot系列——消息中间件ActiveMQ——2:基本概念以及多元化使用

ActiveMQ概念:

  1. Queue - Point-to-Point (点对点)
    一条消息只能被一个消费者消费, 且是持久化消息 - 当没有可用的消费者时,该消息保存直到被消费为止;当消息被消费者收到但不响应时(具体等待响应时间是多久,如何设置,暂时还没去了解),该消息会一直保留或会转到另一个消费者当有多个消费者的情况下。当一个Queue有多可用消费者时,可以在这些消费者中起到负载均衡的作用。
  2. Topic - Publisher/Subscriber Model (发布/订阅者)
    一条消息发布时,所有的订阅者都会收到,topic有2种模式,Nondurable subscription(非持久订阅)和durable subscription (持久化订阅 - 每个持久订阅者,都相当于一个持久化的queue的客户端), 默认是非持久订阅。
  • 持久化:消息产生后,会保存到文件/DB中,直到消息被消费, 如上述Queue的持久化消息。默认保存在ActiveMQ中:%ActiveMQ_Home%/data/kahadb
  • 非持久化:消息不会保存,若当下没有可用的消费者时,消息丢失。

点对点(PTP)消息通信模型

也可称之为队列Queue模式,特定的一条消息只能被一个消费者消费。生产者将消息发送到指定的Queue当中,Broker(中间件)针对消息是否需要持久化进行持久化存储后通知消费者进行处理,消费者处理完毕后发送一个回执(Acknowledge)给Broker,Broker认为该消息已被正常消费,于是从持久化存储中删除该条消息,回执的发送逻辑内嵌在MQ的API中,无需主动调用。消费者通常可以通过两种方式获取新消息:Push和Pull。Push方式:由ActiveMQ收到消息后主动调用消费者的新消息通知接口,需要消耗ActiveMQ宝贵的线程资源,同时消费者只能被动等待消息通知。Pull方式:由消费者轮询调用 ActiveMQ API 去获取消息,不消耗ActiveMQ 线程,消费者更加主动,虽然消费者的处理逻辑变得稍稍复杂。两种方式的根本区别在于线程消耗问题,由于ActiveMQ 的线程资源相对客户端更加宝贵,Push方式会占用ActiveMQ 过多的线程从而难以适应高并发的消息场景。同时当某一消费者离线一段时间再次上线后,大量积压消息处理会消耗大量ActiveMQ 线程从而拖累其它消费者的消息处理,所以Pull方式相对来说更好(Kafka消息中间件已经抛弃了PUSH模式,全面拥抱PULL模式)。

发布/订阅模式(Pub/Sub)

也可称之为主题Topic模式,特定的一条消息可以被多个消费者所接收,只要消费者订阅了某个主题。消息生产者(发布者)将消息发送到某个称为主题(Topic)的虚拟通道中,Topic可以被多个消费者订阅,因此该模式类似于广播的方式。发布/订阅模式采用PUSH的方式传送消息,Subscriber只需保持在线即可。Subscriber分为临时性的和持久性的,当订阅者离线时,ActiveMQ 会为持久性的Sub持久化消息,当Sub恢复时会重新收到消息。但是既然采用Pub/Sub模式就表明允许部分消费者接收不到消息,所以通常会采用临时性的Subscriber而不是持久性的。

默认只能发送和接收queue消息

测试效果:

有两个相同的项目,A与B

通过A发送消息,A接收到消息

通过B发送项目,B接收到消息,

如果把A项目的接收消息功能关闭,通过A发送消息,B接收消息

Queue 与Topic 自由切换

如果要发送和接收topic消息,需要在application.properties文件中加入:

spring.jms.pub-sub-domain=true

新建一个JMS的配置类:

@Configuration
public class JmsConfig {
	public final static String TOPIC = "springboot.topic.test";
	public final static String QUEUE = "springboot.queue.test";

	@Bean
	public Queue queue() {
		return new ActiveMQQueue(QUEUE);
	}

	@Bean
	public Topic topic() {
		return new ActiveMQTopic(TOPIC);
	}

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

	// queue模式的ListenerContainer
	@Bean
	public JmsListenerContainerFactory<?> jmsListenerContainerQueue(ConnectionFactory activeMQConnectionFactory) {
		DefaultJmsListenerContainerFactory bean = new DefaultJmsListenerContainerFactory();
		bean.setConnectionFactory(activeMQConnectionFactory);
		return bean;
	}

}

消息发送者

@RestController
@RequestMapping(value = "/active_mq2/producer")
public class ActiveMQProducerController2 {
	@Autowired
	private JmsMessagingTemplate jmsTemplate;
	@Autowired
	private Topic topic;
	@Autowired
	private Queue queue;

	@RequestMapping("/send_topic")
	public String sendTopic(HttpServletRequest request) {
		jmsTemplate.convertAndSend(topic, request.getParameter("msg"));

		return "msg发送成功";

	}

	@RequestMapping("/send_queue")
	public String sendQueue(HttpServletRequest request) {
		jmsTemplate.convertAndSend(queue, request.getParameter("msg"));

		return "msg发送成功";

	}

}

消息接收者

@Component
public class ActiveMQConsumer2 {
	@JmsListener(destination = JmsConfig.TOPIC, containerFactory = "jmsListenerContainerTopic")
	public void onTopicMessage(String msg) {
		System.out.println("TOPIC==============msg===============" + msg);
	}

	@JmsListener(destination = JmsConfig.QUEUE, containerFactory = "jmsListenerContainerQueue")
	public void onQueueMessage(String msg) {
		System.out.println("QUEUE==============msg===============" + msg);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值