首先看一下在java程序里面是如何利用jmsAPI使用activeMQ的
首先是发送一条消息的简单demo’
public class JMSCommonProducer {
public static void main(String[] args) throws JMSException {
//根据broker URL建立连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.0.15:61616");
//创建连接
Connection connection = connectionFactory.createConnection();
//创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
connection.start();
//创建队列(有则不创建)
Destination destination = session.createQueue("garine-queue");
//创建生产者
MessageProducer producer = session.createProducer(destination);
//创建文本消息,有多种消息类型
TextMessage textMessage = session.createTextMessage("Hello garine");
//发送消息
producer.send(textMessage);
System.out.println("over");
}
}
然后就是消费一条消息的简单demo
public class JMSCommonConsumer {
public static void main(String[] args) throws JMSException {
//根据broker URL建立连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.0.15:61616");
//创建连接
Connection connection = connectionFactory.createConnection();
connection.start();
//创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建队列(有则不创建)
Destination destination = session.createQueue("garine-queue");
//创建生产者
MessageConsumer consumer = session.createConsumer(destination);
//接受文本消息,阻塞等待
TextMessage textMessage = (TextMessage) consumer.receive();
System.out.println(textMessage.getText());
session.close();
}
}
基于以上的基本代码展开,介绍activemq的一些特性
JMS消息类型
除了基础demo中使用的TextMessage,jms还支持其他四种消息类型,总共有五种:
TextMessage:java.lang.String 对象,如 xml 文件内 容
MapMessage:键/值对的集合,键值是String对象,值 类型可以是Java任何基本类型
BytesMessage:字节对象
StreamMessage:java中的io流
ObjectMessage:可序列化的java对象
Message:没有消息体,只有消息头部和属性的JMS消息
下面尝试传送ObjectMessage,新建一个可序列化对象,发送代码如下:
public class JMSObjectProducer {
public static void main(String[] args) throws JMSException {
//根据broker URL建立连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.0.15:61616");
//创建连接
Connection connection = connectionFactory.createConnection();
connection.start();
//创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建队列(有则不创建)
Destination destination = session.createQueue("garine-queue");
//创建生产者
MessageProducer producer = session.createProducer(destination);
//创建文本消息,有多种消息类型
ObjectMessage objectMessage = session.createObjectMessage(new SerializableObject());
//发送消息
producer.send(objectMessage);
System.out.println("over");
session.close();
}
}
接收端代码
public class JMSObjectConsumer {
public static void main(String[] args) throws JMSException {
//根据broker URL建立连接工厂
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.0.15:61616");
connectionFactory.setTrustAllPackages(true);
//创建连接
Connection connection = connectionFactory.createConnection();
connection.start();
//创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建队列(有则不创建)
Destination destination = session.createQueue("garine-queue");
//创建生产者
MessageConsumer consumer = session.createConsumer(destination);
//接受文本消息,阻塞等待
ObjectMessage objectMessage = (ObjectMessage) consumer.receive();
System.out.println(objectMessage.getObject());
session.close();
}
}
总之就是按照我们的需求构造相应的消息,JMS规范让我们使用activeMQ进行java服务之间消息通信时简单快捷,灵活性很高。
消息模型
跟大多数消息中间件一样,activeMQ提供p2p,pub/sub的消息模型。
point to point:点对点模型到消息只能被一个消费者消费;activemq中队列形式是p2p模型;一个队列可以多个消费者,但是只能被一个消费者消费;当无消费者时消息可以积压在队列,等到消费者上线时再消费也可以;
publish/subcrible:发布/订阅模式,一条消息能给多个消费者消费;activemq中topic形式是pub/sub模式;
而针对publish/subcrible,又延伸出持久订阅和非持久订阅两种模式,需要注意的是,这是针对topic的消息模型而言的
非持久订阅:只能接收在线时topic发布到消息
持久订阅:能够接收在下线时topic发布到消息,不过在下线之前必须已经注册了持久订阅到topic,这样当离线时,broker会为这个持久订阅保留消息
demo中演示的是p2p形式的代码,下面看一下topic持久化订阅的如何实现
public class JMSTopicProducer {
public static void main(String[] args) throws JMSException {
//根据broker URL建立连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.0.15:61616");
//创建连接
Connection connection = connectionFactory.createConnection();
connection.start();
//创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创topic(有则不创建)
Topic destination = session.createTopic("garine-topic");
//创建生产者
MessageProducer producer = session.createProducer(destination);
//创建文本消息,有多种消息类型
TextMessage textMessage = session.createTextMessage("Hello garine");
//发送消息
producer.send(textMessage);
System.out.println("over");
session.close();
}
}
public class JMSPersistenTopicConsumer {
public static void main(String[] args) throws JMSException {
//根据broker URL建立连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.0.15:61616");
//创建连接
Connection connection = connectionFactory.createConnection();
connection.setClientID("persistent-sub-id");
connection.start();
//创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建topic(有则不创建)
Topic topic = session.createTopic("garine-topic");
//创建消费者
MessageConsumer consumer = session.createDurableSubscriber(topic, "persistent-sub-id");
//接受文本消息,阻塞等待
TextMessage textMessage = (TextMessage) consumer.receive();
System.out.println(textMessage.getText());
session.close();
}
}
activeMQ中的会话事务性
事务性会话
特性:
对于消息发送方,消息在session.commi时才会发送到broker,如果session.rollback,那么未提交到消息都作废;
对于消息消费者,消息在session.commit之后,才会进行ack,如果session.rollback,那么会表示broker可以重新发送消息给消费者。必须保证发送端和接收都是事务性会话。
因此开启的事务性会话,提交消息到ack都必须通过session.commit();
非事务性会话
对于发送消息,不需要session.commit,直接发送给broker;
对于消费消息的ack,简单说有以下的特性,后续会展开详细说名ack机制。
非事务性会话的主要特性是其ack模式的特殊
Session.AUTO_ACKNOWLEDGE: 接收到消息时,自动ack确认消息
Session.CLIENT_ACKNOWLEDGE:接收到消息时,客户端调用message.acknowledge(),显式对消息确认。需要注意对是,消息确认时,如果在本次消息确认之前还有别的消息未确认,会在本次消息确认时一并确认,也就是批量确认消息。在activeMQ中批量拉取和批量确认消息是优化的重要手段,后面介绍,目前先记住—>消费端处理流程以及优化策略。
Session.DUPS_ACKNOWLEDGE:延迟消息确认,broker端没有收到消息确认时自动重发消息,不在乎消费端接收多次消息
demo中的是未开始事务性会话,如果要开启,可以改为如下一段代码
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
如果需要改变消费端消息确认的方式,那么请不要开启事务会话,并且做如下改变,Session.xxxxxxxx是想要的消息确认方式
Session session = connection.createSession(true, Session.xxxxxxxx);
消息持久化存储
持久化存储针对消息发送方,需要设置消息投递模式为DeliveryMode.PERSISTENT,broker会在接收到消息时存储消息到存储介质,再进行消息分派。
目前支持以下五种持久化策略,详细的持久化策略介绍—>activeMQ持久化策略
Ø KahaDB存储(默认存储方式)
Ø JDBC存储
Ø Memory存储
Ø LevelDB存储
Ø JDBC With ActiveMQ Journal
发送持久化消息可以按照如下方式
//创建持久化文本消息
TextMessage textMessage = session.createTextMessage("Hello garine");
textMessage.setJMSDeliveryMode(DeliveryMode.PERSISTENT);
异步监听消费
最后还有一个就是异步监听消费消息,这是我们常用的代码模式,消费者代码如下:
public class JMSAsyncConsumer {
public static void main(String[] args) throws JMSException {
//根据broker URL建立连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.0.15:61616");
//创建连接
Connection connection = connectionFactory.createConnection();
connection.start();
//创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建队列(有则不创建)
Destination destination = session.createQueue("garine-queue");
//创建生产者
MessageConsumer consumer = session.createConsumer(destination);
//异步接受文本消息,在回调函数处理消息
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println(textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
});
//session.close();
}
}
需要注意的是绝对不能关闭session,否则无法监听消息。
以上是大部分activeMQ使用需要注意的点以及特性,是大部分场景下使用activeMq方式。