这里写目录标题
下载安装
- 官网下载.
- 解压后进入 bin 目录
./activemq start
启动 - activemq默认端口为 61616
- activemq 前台端口默认为 8161
- 用户名密码默认是 admin admin
基本概念
引入依赖
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>4.5</version>
</dependency>
JMS 总体架构图
TOPIC. (主备)
QUEUE(负载均衡)
编码
Queue
生产者代码
public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("my-queue");
MessageProducer producer = session.createProducer(queue);
TextMessage textMessage = session.createTextMessage("哈哈,这是消息");
producer.send(textMessage);
producer.close();
session.close();
connection.close();
}
消费者代码
public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("my-queue");
MessageConsumer consumer = session.createConsumer(queue);
while (true){
Message message = consumer.receive();
if (message == null){
break;
}
TextMessage msg = (TextMessage)message;
System.out.println(msg.getText());
}
consumer.close();
session.close();
connection.close();
}
Topic
消费者
public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("my-topic");
MessageConsumer consumer = session.createConsumer(topic);
while (true){
Message message = consumer.receive();
if (message == null){
break;
}
TextMessage msg = (TextMessage)message;
System.out.println(msg.getText());
}
consumer.close();
session.close();
connection.close();
}
生产者
public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("my-topic");
MessageProducer producer = session.createProducer(topic);
TextMessage textMessage = session.createTextMessage("哈哈,这是topic的消息");
producer.send(textMessage);
producer.close();
session.close();
connection.close();
}
Topic和Queue的对比
- 当没有消费者的时候,发送到Queue 的数据,在消费者启动之后会消费之前的数据.而Topic的消息如果发送的时候没有消费者,那么发送了就丢失了
- Queue 是负载均衡策略,所以再多的消费者,queue的性能也不会有影响,而topic会随着消费者增多,性能下降
JMS
java message service 是JavaEE 的一个技术
JMS 组成结构和特点
- JMS Provider
实现JMS规范的消息中间件,也就是MQ服务器
- JMS Producer
消息生产者,是MQ客户端
- JMS Consumer
消息消费者,是MQ客户端
JMS Message
- 消息头
JMSDestination: message 可以设置目的地, 亲测无效,目的地还是按照producer指定发送
JMSDeleveryMode: 分为持久化和非持久化, 非持久化的消息在MQ重启之后就消失了
JMSExpiration: 超时时间,不懂有什么用
JMSPriority : 优先级,也觉得没什么用
JMSMessageID : 消息的唯一id,可以用来保证消息的幂等性 - 消息体
有5中消息体,常用的就用TextMessage
就好了,Map 其他格式都可以自己转换 - 消息属性
一个kv键值对.在message 中 setStringProperty 之后可以从消费者里面取出来.
消息的可靠性
消息的持久化
/**
消息设置持久化
*/
textMessage.setJMSDeliveryMode(DeliveryMode.PERSISTENT);
textMessage.setJMSDeliveryMode(DeliveryMode.NON_PERSISTENT);
/**
生产者设置持久化
*/
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
Queue 默认就是持久化的模式,而Topic 默认是非持久化模式
消息的可靠性分为两个方面,一个是生产者发送到MQ时候的可靠性,另一个是MQ发送到消费者之前,消息不会丢失
Queue 的持久化是默认的,而Topic 的持久化需要修改代码
因为topic的生产者就算设置了持久化的参数,根据topic 的性质,在发送的时候,没有消费者,这条消息也就作废了,所以代码需要修改
消息的生产者. connection.start
方法要往后放.
public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("persistent-topic");
MessageProducer producer = session.createProducer(topic);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
TextMessage textMessage = session.createTextMessage("这是持久化的topic消息");
connection.start();
producer.send(textMessage);
producer.close();
session.close();
connection.close();
}
消费者则需要在 connection 上添加id 和 使用 不一样的consumer
public static void main(String[] args) throws Exception{
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
connection.setClientID("consumer-01");
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic("persistent-topic");
TopicSubscriber consumer = session.createDurableSubscriber(topic, "");
connection.start();
while (true){
Message message = consumer.receive();
if (message == null){
break;
}
TextMessage msg = (TextMessage)message;
System.out.println(msg.getText());
}
consumer.close();
session.close();
connection.close();
}
topic持久化需要先启动一次消费者,让MQ知道有这么一个id的消费者想要消费这个topic,当该消费者离线再次上线的时候MQ就会把没有消费的消费再发送给消费者
事务
当 connection 在创建 session 的时候,需要传两个参数, 第一个是 是否启用事务
第二个是 签收的级别
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
生产者
如果事务是false , producer 执行send操作,消息就会被发送到队列中.
而如果是true,则需要执行session.commit操作,消息才会被发送到MQ中
消费者
如果消费者配置事务为true,则消费之后也需要将session.commit,不然下次启动还会消费到同样的消息.
ACK模式. 消费者和MQ之间的事情
ACK模式适用于非事务情况,事务的情况下ACK参数无效
消费结束的消息需要调用 acknowledge 方法告诉MQ这条消息已经成功消费了