下载地址:https://activemq.apache.org/activemq-5015009-release
订单秒杀系统下单之后存在在业务的流程
(读取订单、库存检查、库存冻结、余额检查、余额冻结、订单生成、余额扣减、库存扣减、生成流水、余额冻结、库存解冻)
RPC接口基本是同步调用,整体的服务性能遵循“木桶理论”,即整体系统的耗时取决于最慢的那个接口。比如A调用B/C/D都是50 ms,但是B调用B1花费的时间为2000 ms,那么将会拖累整个系统的服务性能。
注:在设计系统时,明确达到的目标
消息中间件的作用:解耦、削峰、异步;
定义:发送者把消息发送给消息服务器,消息服务器将消息存放在若干队列/主题中,在合适的时候,消息服务器会将消息转发给消息接收者。在这个过程中,发送和接收都是异步的,也就是发送无需等待,而且发送者和接收者的生命周期也没有必然的关系;尤其在发布pub/订阅sub模式下,也可以完成一对多的通信,即让一个消息有多个接收者。
队列(queue):相当于发短信,一对一。
主题(topic):相当于朋友圈,需要订阅,公众号;一对多。
特点
注:建议下载linux版本,消息队列大多数情况都是在集群的环境下进行部署,而集群的使用大多数是使用linux
./activemq start #启动
./activemq stop #关闭
./activemq restart #重启
netstat -anp|grep 61616
lsof -i 61616
ps -ef|grep activemq
#可以访问http://localhost:8161 可现可视化界面
#默认的用户名/密码: admin/admin
注:页面访问,点击进行登录
./activemq start > 路径/run_activemq.log
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.9</version>
</dependency>
注:ActiveMQ的访问地址的方式为tcp的方式
进行生产者进行消息发送
//生产者
public static void queueDemo() throws JMSException {
String path="tcp://192.168.160.128:61616/";
String name ="queue01";
//创建连接工厂,采用默认的用户名和密码
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(path);
//创建连接并启动
Connection connection = connectionFactory.createConnection();
connection.start();
//创建会话session,第一个参数是事务,第二个参数是签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建目的地
Queue queue = session.createQueue(name);
//创建消息生产者
MessageProducer producer = session.createProducer(queue);
//进行消息发送
for (int i =0;i<3;i++){
//创建消息
String message = "这是第"+i+"条消息";
//创建消息
Message textMessage = session.createTextMessage(message);
//消息发送
producer.send(textMessage);
}
producer.close();
session.close();
connection.close();
System.err.println("消息发送完成");
}
//消费者
public static void queueConsumersDemo() throws JMSException {
String path = "tcp://192.168.160.128:61616";
String name ="queue01";
//创建连接工厂
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(path);
//创建链接
Connection connection = connectionFactory.createConnection();
//启动
connection.start();
//创建session
Session session = connection.createSession(false, AUTO_ACKNOWLEDGE);
//创建消费者
Queue queue = session.createQueue(name);
//创建消费者
MessageConsumer consumer = session.createConsumer(queue);
while (true){
//可以通过recive设置等待时间,当超时时,消费者自动关闭
//Message receive = consumer.receive(4000L);
Message receive = consumer.receive();
if (receive != null){
System.err.println(receive);
}
}
}
注:tcp对应的进程的端口为61616,注意连接的地址
队列监听setMessageListener
public static void setListener() throws JMSException, IOException {
ActiveMQConnectionFactory MQ = new ActiveMQConnectionFactory(path);
Connection conn = MQ.createConnection();
conn.start();
Session session = conn.createSession(false, AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(name);
MessageConsumer consumer = session.createConsumer(queue);
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
if (message!=null ){
try {
// TextMessage receive = (TextMessage) consumer.receive();
TextMessage textMessage = (TextMessage) message;
System.out.println("==>>>"+textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
});
//防止后台关闭,对MQ进行监听,当有消息的时候进行输出
System.in.read();
consumer.close();
session.close();
conn.close();
}
在当多个消费者进行等待,之后生产者进行消息的产生,每个消费者对消息进行平均分配,类似于负载均衡。
例:当两个消费者在进行等待时,生产者产生6条消息,则两个消费者对者6条消息进行平均分配,没人三条。
特点:
JMS规范允许客户创建持久订阅,还在一定程度上放松了时间上的相关性要求。持久订阅允许消费者消费它在未处于激活状态时发送的消息。一句话,类似于微信公众号的订阅
//主题生产者
public static void topicProduce() throws JMSException {
ActiveMQConnectionFactory mq = new ActiveMQConnectionFactory(path);
Connection connection = mq.createConnection();
connection.start();
Session session = connection.createSession(false, AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(topicName);
MessageProducer producer = session.createProducer(topic);
for (int i =0; i <3; i++){
String tpc = "这是第一条消息";
TextMessage textMessage = session.createTextMessage(tpc);
producer.send(textMessage);
}
producer.close();
session.close();
connection.close();
System.err.println("主题发送成功====");
}
//创建消费者
public static void topicConsumer() throws JMSException, IOException {
ActiveMQConnectionFactory mq = new ActiveMQConnectionFactory(path);
Connection connection = mq.createConnection();
connection.start();
Session session = connection.createSession(false, AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(topicName);
MessageConsumer consumer = session.createConsumer(topic);
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
TextMessage textMessage = (TextMessage) message;
try {
System.err.println("============="+textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
});
System.in.read();
consumer.close();
session.close();
connection.close();
}
注:主题的启动顺序,先启动消费者,在启动生产者。消费者每个都会得到一份生产者发出的所有的信息。
JavaEE是一套使用Java进行企业级应用开发的大家一直遵循的13个核心规范工业标准。JavaEE平台提供了一个基于组件的方法来加快设计、开发、装配即部署企业应用程序。
Java消息服务是指的两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供了一组通用接口,包括创建、发送、读取消息等,用于支持Java应用程序的开发,在JavaEE中,当两个应用程序使用JMS进行通信时,他们之间并不是直接相连,而是通过一个共同的消息收发服务组件关联起来以达到解耦、异步、削峰的效果
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|---|
单机吞吐量 | 万级,比 RocketMQ、Kafka 低一个数量级 | 同 ActiveMQ | 10 万级,支撑高吞吐 | 10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
opic 数量对吞吐量的影响 | topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic | topic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源 | ||
时效性 | ms 级 | 微秒级,这是 RabbitMQ 的一大特点,延迟最低 | ms 级 | 延迟在 ms 级以内 |
可用性 | 高,基于主从架构实现高可用 | 同 ActiveMQ | 非常高,分布式架构 | 非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息可靠性 | 有较低的概率丢失数据 | 基本不丢 | 经过参数优化配置,可以做到 0 丢失 | 同 RocketMQ |
功能支持 | MQ 领域的功能极其完备 | 基于 erlang 开发,并发能力很强,性能极好,延时很低 | MQ 功能较为完善,还是分布式的,扩展性好 | 功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用 |
其他 | Apache软件基金会开发、起步较早,但没有经过大量吞吐场景验证,目前社区不是很活跃 | 开源,稳定,社区活跃度高 | 阿里出品,目前已交给Apache,但社区活跃度较低 | Apache软件基金会开发、开源、高通吐量,社区活跃度高 |
注:发送什么类型的消息,就得接收什么类型的消息,要一一对应。
消息持久模式与非持久模式
消息头属性
消息体的五种属性
消息属性
如果需要除消息头字段以外的值,那么可以使用消息属性,识别/去重/重点标注等操作非常有用的方法。他们是以属性名和**属性值对(K:V)**的形式指定的,可以将属性是为消息头的扩展,属性指定一些消息头没有包括的附加消息,比如可以在属性里指定消息选择器。
消息的属性就像可以分配给一条消息的附加消息头一样,他们可以允许开发者添加有关消息的不透明附加消息,他们还用于暴漏消息选择器在消息过滤是使用的数据。
例:
TextMessage message = session.createTextMessage();
message.setText(text);
message.setStringProperty("username","ABC")// 进行消息自定义
消息队列中,默认的消息为消息持久化
采用持久性消息,当ActiveMQ宕机时,未消费的消息的数量保持不变,有利于保持消息而不被丢失。
队列的默认传送模式,此模式保证这些消息被成功的发送一次和成功的使用一次。对于这些消息可靠性是优先考虑的因素。
可靠性另一个重要的方面是确保持久性消息传送至目标后,消息服务在向消费者传送它们之前不会丢失这些消息。
//持久化主题,消息消费者
public static void lastingTopicConsumer() throws JMSException, IOException {
ActiveMQConnectionFactory mq = new ActiveMQConnectionFactory(path);
Connection connection = mq.createConnection();
connection.setClientID(name);
Session session = connection.createSession(false, AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(topicName);
TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic,"remark...");
connection.start();
//主题的订阅者
Message receive = topicSubscriber.receive();
while (receive!=null){
TextMessage textMessage =(TextMessage) receive;
System.out.println("====="+textMessage.getText());
receive = topicSubscriber.receive(5000);
}
System.in.read();
session.close();
connection.close();
}
定义:相当于一个ActiveMQ服务器实例
Broker其实就是实现了用代码的形式启动ActiveMQ将MQ嵌入到Java代码中,以便随时用随时启动,
在用的时候再去启动这样节省了资源,也保证了可靠性。
方式:
用ActiveMQ Broker作为独立的消息服务器来构建java应用
ActiveMQ也支持在VM中通信基于嵌入式的broker,能够无缝的集成其他java应用
所需mvn依赖
//ActiveMQ核心依赖
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.9</version>
</dependency>
// 整合spring所需要的依赖
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>3.16</version>
</dependency>
//进行json数据格式转换,在进行Java内嵌activqMQ时,需要引进,否则会报错
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
代码实现
//相当于在本机上边开启了一个ActiveMQ的服务
public static void main(String[] args) throws Exception {
BrokerService brokerService = new BrokerService();
brokerService.setUseJmx(true);
brokerService.addConnector("tcp://localhost:61616");
brokerService.start();
}
application.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.atguigu.activemq"/>
<bean id="jmsFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp:192.168.160.128"/>
bean>
property>
<property name="maxConnections" value="100"/>
bean>
<bean id="destinationQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="spring-active-queue"/>
bean>
<bean id="jsmTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsFactory"/>
<property name="defaultDestination" ref="destinationQueue"/>
<property name="messageConverter">
<bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
property>
bean>
beans>
生产者
package com.atguigu.activemq;
import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Service;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import javax.jms.TextMessage;
@Service
public class Producer {
@Autowired
private JmsTemplate jmsTemplate;
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Producer producer =(Producer) applicationContext.getBean("Producer");
producer.jmsTemplate.send(new MessageCreator() {
@Override
public Message createMessage(Session session) throws JMSException {
TextMessage textMessage = session.createTextMessage("********当前消息");
return textMessage;
}
});
}
}
消费者
package com.atguigu.activemq;
import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
@Service
public class Customer {
@Autowired
private JmsTemplate jmsTemplate;
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Customer customer =(Customer) applicationContext.getBean("Customer");
String receiveAndConvert =(String) customer.jmsTemplate.receiveAndConvert();
System.out.println(receiveAndConvert);
}
}
mvn依赖
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>ActiveMQDemoartifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.apache.activemqgroupId>
<artifactId>activemq-allartifactId>
<version>5.15.9version>
dependency>
<dependency>
<groupId>org.apache.xbeangroupId>
<artifactId>xbean-springartifactId>
<version>3.16version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.9.5version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jmsartifactId>
<version>4.3.23.RELEASEversion>
dependency>
<dependency>
<groupId>org.apache.activemqgroupId>
<artifactId>activemq-poolartifactId>
<version>5.15.9version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>4.3.23.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>4.3.23.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>4.3.23.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-ormartifactId>
<version>4.3.23.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjrtartifactId>
<version>1.6.1version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.6.8version>
dependency>
<dependency>
<groupId>cglibgroupId>
<artifactId>cglibartifactId>
<version>2.1_2version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>1.7.25version>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>1.2.3version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.16.18version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
dependencies>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
project>
注:在ActiveMQ中默认的使用TCP协议,也默认支持多种的传输协议
设置支持NIO网络协议
<transportConnector name="nio" uri="nio://0.0.0.0:61618"/>
设置进行多协议支持,在5.13之后在支持auto多协议同时支持
<transportConnector name="auto+nio" uri="auto+nio://0.0.0.0:61617?auto.protocols=default,stomp"/>
为了避免以为宕机之后数据的丢失,需要做到重启之后可以恢复消息队列,消息系统一般都会采用持久化机制。ActiveMQ的消息持久化机制又JDBC、AMQ、KahaDB(默认使用)、LevelDB,无论使用哪一种持久化的机制,消息存储的逻辑都是一致的。
消息存储机制:
就是在发送者在发送出去之后,消息中心首先将消息存储到本地的数据文件、内存数据库或者远程数据库等在试图将消息在发送给接收者,成功则将消息从存储中进行删除,失败则继续尝试发送。消息中心启动以后首先要检查指定的存储位置,如果有未发送成功的消息,则需要将消息发送出去。
KahaDB:在5.3版本之后建议推荐使用KahaDB存储方式,在5.4版本之后,默认使用kahaDB存储方式
默认的文件的存储位置在activeMQ下的data文件中
注:对于长时间的存储,建议使用JDBC的存储方式
<persistenceAdapter>
<jdbcPersistenceAdapter dataSource="#mysql-ds" createTablesOnStartup="true"/>
persistenceAdapter>
dataSource指定将要引用的持久化数据库的bean名称;
createTablesOnStartup 是否在启动的时候创建数据表,默认值是true;
这样每次启动都会去创建数据表,一般是第一次启动的时候设置为true 之后改成false;
relaxAutoCommit 表示进行自动提交
<bean id="mysql-ds" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/activemq?relaxAutoCommit=true"/>
<property name="username" value="activemq"/>
<property name="password" value="activemq"/>
<property name="poolPreparedStatements" value="true"/>
bean>
注:注意配置信息将要添加的位置,否则可能会报错:
ACTIVEMQ_MSGS表字段:
ID:自增数据库主键
CONTAINER:消息的Destination
MSGID_PROD:消息发送者的主键
MSG_SEQ:是发下哦那个消息的顺序,MSGID_PROD+MSG_SEQ可以足证JMS的MessageID
EXPIRATION:消息的过期时间,存储的是从1970-01-01
MSG:消息本体的Java序列对象的二进制数据
PRIORITY:优先级,0-9,数值越大优先级越高
ACTIVEMQ_ACKS表字段:用于存储订阅关系,如果是持久化topic,订阅者和服务器的订阅关系在这个表里面进行保存;
CONTAINER:消息的介绍
SUB_DEST:如果使用的是Static集群,这个字段会有集群其他系统的信息
CLIENT_ID:每个订阅者都必须有一个唯一的客户端ID用以区分
SUB_NAME:订阅者名称
SELECTOR:选择器,可以选择之消费满足条件的信息,条件可以用自定义的属性进行实现,支持多属性AND和OR
LAST_ACKED_ID:记录消费过的消息的ID
可能出现的错误
解决方法:
在保证activeMQ在使用JDBC消息持久化时,所需要的jar包,以及数据库密码,用户、地址都没有错误的情况下,造成报错的原因可能是数据库远程连接的权限没有被放开,导致数据库在进行远程连接时,连接失败。这种情况下,需要放开数据库远程连接的权限。
mysql -u root -p
show databases;
use mysql;
select User,Host from user;
注:如果权限没有被放开的情况下,root所对应的Host为localhost,这是我们需要将其改为%
update set Host='%' where User='root';
flush privileges;
注:在修改完成之后一定要进行配置刷新,否则相关修改不起作用
注:在使用消息持久化存储机制时,一定要将activeMQ设置为持久化。否则不会将信息存储到数据库中
点对点类型
在DeliveryMode设置为NODE_PERSISTENCE(非持久化)时,消息保存在内存中
在DeliveryMode设置为PERSISTENCE(持久化),消息保存在broker的相应的文件或者数据库中
而且点对点类型中消息一旦被消费,消息就会在存储的位置进行删除操作。
在使用Topic时,在消息持久化,消息在被消费的时候,消息不会被删除。
如果是queue
在没有消费者消费的情况下会将信息保存在activemq_msgs表中,只要有任意消费者已经消费过了,消费之后这些消息将被删除。
如果时topic
一般是先启动消费订阅然后在生产的情况下,会将消息保存到activemq_acks表中
数据库jar包
记得需要使用到的相关的jar文件,放置到lib目录下,mysql-jdbc驱动的jar包和对应的数据库连接池的jar包。默认是dbcp
createTableOnStartup属性
在jdbcPersistenceAdapter标签中设置了createTableOnStartup属性为true时,在第一次启动ActiveMQ时,ActiveMQ服务节点会自动在数据库中创建相关的数据库表,启动完成后可以去掉这个属性,或者是将属性值修改为false。其属性值默认为true,建议在不用的时候将属性值,修改为false
下划线的问题
“java.lang.lllegalStateExcepton:BeanFactory not initialized or already closed”
产生报错的原因是因为您的操作系统的机器名中存在“_”符号,请修改机器名并重启可以解决相关问题。
在activemq.xml中进行配置
<persistenceFactory>
<journalPersistenceAdapterFactory journalLogFiles="4"
journalLogFileSize=""
useJournal="true"
useQuickJournal="true"
dataSource="#mysql-ds"
dataDirectory="activemq-data"/>
persistenceFactory>
配置完成之后,对activeMQ进行重启操作
注:ActiveMQ默认的消息发送方式为异步传输,但是建议在进行代码编写时,再次将消息传输的方式设置为异步
注:当消息设置为不采用事务,但是却将消息设置为持久化时,MQ会默认将消息的传输 方式设置为同步消息传输。这样的传输方式,只有当消息发送出去之后,只有被接受返回成功之后,才会进行下一个消息的处理,容易造成堵塞。
注:在进行异步消息传输时,MQ允许存在极少量的数据丢失,也会存在极少量数据丢失的情况。
例:
cf = new ActiveMQConnectionFactory("tcp://locahost:61616?jms.useAsyncSend=true");
((ActiveMQConnectionFactory)connectionFactory).setUseAsyncSend(true);
((ActiveMQConnection)connection).setUseAsyncSend(true);
注:在使用异步消息队列是,注意要采用消息的回调,来确认消息是否发送成功
public static void queueDemo() throws JMSException {
// String path="tcp://192.168.160.128:61616/";
String name ="queue01";
//创建连接工厂,采用默认的用户名和密码
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://locahost:61616?jms.useAsyncSend=true");
//创建连接并启动
Connection connection = connectionFactory.createConnection();
connection.start();
//创建会话session,第一个参数是事务,第二个参数是签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建目的地
Queue queue = session.createQueue(name);
//创建消息生产者
ActiveMQMessageProducer producer = (ActiveMQMessageProducer) session.createProducer(queue);
//进行消息发送
for (int i =0;i<3;i++){
//创建消息
String message = "这是第"+i+"条消息";
//创建消息
Message textMessage = session.createTextMessage(message);
textMessage.setJMSMessageID(UUID.randomUUID().toString().replaceAll("-","")); //设置消息的id
//消息发送
producer.send(textMessage, new AsyncCallback() {
@Override
public void onSuccess() {
//进行消息的回调
System.out.println("发送成功的消息"+textMessage.toString());
}
@Override
public void onException(JMSException e) {
//进行消息的回调
System.out.println("发送失败的消息"+textMessage.toString());
}
});
}
producer.close();
session.close();
connection.close();
System.err.println("消息发送完成");
}
官网地址:https://activemq.apache.org/redelivery-policy
引起消息重发的情况
Client用了transaction且在session中调用了rollback();(没被签收被回调)
Client用了transactions且在调用commit()之前关闭或者时没有commit(事务没有被提交)
Client在CLIENT_ACKNOWLEDGE的传递模式下,在session中调用了recover()
默认:每一秒钟发送6次,当消息发送超过最大次数时,该消息会被标志位异常消息,最终会被存储到死信队列中
常用属性:
处理发送失败的消息
将所有的DeadLetter保存到一个共享的队列之中,是ActiveMQ的默认的策略
共享队列默认为ActiveMQ.DLQ可以通过deadLetterQueue属性进行设定
<deadLetterStratege>
<shareDeadLetterStrategy deadLetterQueue="DLQ-QUEUE"/>
deadLetterStratege>
可以将定时自动删除死信队列中的消息,或者可以存储非持久的异常消息
可以通过radis进行相关的解决