ActiveMQ

本文深入解析消息中间件的工作原理,包括点对点(P2P)和发布订阅两种消息模型,详细介绍了如何使用Java消息服务(JMS)实现这两种模式,同时探讨了ActiveMQ的可靠性和持久化机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是消息中间件

面向消息的中间件,发送者将消息发送给消息服务器,消息服务器将消息存放在队列中,在合适的时候在将消息转发给接收者。

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

jms

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

消息模型

点对点(p2p):每个消息只有一个消费者,一旦被消费,消息就不在消息队列中。发送者和接收者之间在时间上没有依赖性,也就是说当发送者发送了消息之后,不管接收者有没有正在运行,它不会影响到消息被发送到队列。接收者在成功接收消息之后需要向队列应答成功。

发布订阅:每个消息可以有多个消费,发布者和订阅者之间有时间上的依赖性,针对某个主题的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息,而且为了消费消息,订阅者必须保持运行的状态。

实现点对点通讯模式

//生产者
public class Producer {
	
	public static void main(String[] args) throws Exception {
		//创建一个activemq工厂
		ActiveMQConnectionFactory activeFactory = 
				new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,ActiveMQConnection.DEFAULT_PASSWORD,"tcp://127.0.0.1:61616");
		//获取一个activemq连接
		Connection connection = activeFactory.createConnection();
		connection.start();
		Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
		// Destination :消息的目的地;消息发送给谁.
		//创建队列的名字
		Destination destinstion = session.createQueue("activemq_a1");
		//消息生产者
		MessageProducer messageProducer = session.createProducer(destinstion);
		//设置不持久化
		messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
		
		for(int i = 1; i<= 5; i++) {
			send(session,messageProducer,i);
		}
		
	}
	
	public static void send(Session session, MessageProducer mp, int i) throws Exception {
		TextMessage textMessage = session.createTextMessage("消息:" + i);
		mp.send(textMessage);
	}
}
//消费者
public class Consumer {
	public static void main(String[] args) throws Exception {
		ActiveMQConnectionFactory activemqConnectionFactory = 
				new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,ActiveMQConnection.DEFAULT_PASSWORD,"tcp://127.0.0.1:61616");
		Connection connection = activemqConnectionFactory.createConnection();
		connection.start();
		Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
		Destination destination = session.createQueue("activemq_a1");
		MessageConsumer messageConsumer = session.createConsumer(destination);
		while(true) {
			TextMessage textMessage = (TextMessage) messageConsumer.receive();
			if(null != textMessage) {
				System.out.println(textMessage.getText());
			}
		}
	}
}

实现发布订阅模式

//发布者
public class Producer {
	public static void main(String[] args) throws Exception {
		System.out.println("发布者启动。。。");
		ActiveMQConnectionFactory activemqConnectionFactory = 
				new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,ActiveMQConnection.DEFAULT_PASSWORD,"tcp://127.0.0.1:61616");
		Connection connection = activemqConnectionFactory.createConnection();
		connection.start();
		Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
		MessageProducer messageProducer = session.createProducer(null);
		messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
		for(int i =1; i<=5; i++) {
			send(session,messageProducer,i);
		}
		
	}
	
	public static void send(Session session, MessageProducer mp, int i) throws Exception {
		TextMessage textMessage = session.createTextMessage("消息:" + i);
		Destination d = session.createTopic("activemy_a1_topic");
		mp.send(d,textMessage);
	}
	
}
public class Consumer {
	public static void main(String[] args) throws Exception {
		System.out.println("订阅者1启动。。。");
		ActiveMQConnectionFactory activemqConnectionFactory = 
				new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER, ActiveMQConnection.DEFAULT_PASSWORD, "tcp://127.0.0.1:61616");
		Connection connection = activemqConnectionFactory.createConnection();
		connection.start();
		Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
		Topic topic = session.createTopic("activemy_a1_topic");
		MessageConsumer mc = session.createConsumer(topic);
		while(true) {
			TextMessage textMessage = (TextMessage) mc.receive();
			if(null != textMessage) {
				System.out.println(textMessage.getText());
			}
		}
	}
}

JMS消息可靠机制

ActiveMQ消息签收机制:客户端成功接收一条消息的标志是一条消息被签收,成功应答。

消息的签收分两种

1.带事物的session,如果session带有事物,并且事物成功提交,则消息被自动签收,如果事物回滚,则消息会被再次传送。

2.不带事物的session,不带事物的session的签收方式,取决于session的配置。

    Session.AUTO_ACKNOWLEDGE  消息自动签收

    Session.GLIENT_ACKNOWLEDGE   手动签收       textMessage.acknowledge();手动签收

    Session.DUPS_OK_ACKNOWLEDGE    不是必须签收,消息可能会重复发送。

//生产者不开启session,客户端必须手动签收模式
Session session = connection.createSession(Boolean.FALSE, Session.CLIENT_ACKNOWLEDGE);
//消费者手动签收
textMessage.acknowledge();



//生产者不开启session,客户端自动签收模式
Session session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);



//事物消息
Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//提交事物
session.commit();

ActiveMQ持久化

//设置消息持久化
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);

使用MQ注意事项

1.消费者代码不要抛出异常,否则activmq默认有重试机制

2.如果代码发生异常,需要发布版本才可以解决的问题,不要使用重试机制,采用日志记录方式,定时job进行补偿

3.如果不需要发布版本解决的问题,可以采用重试机制进行补偿。

消息幂等性,不被重复消费

产生原因:网络延迟传输中,会造成进行MQ重试中,在重试过程中,可能会造成重复消费。

解决方案:使用全局messageid判断消费方便使用同一个,解决幂等性。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值