activemq笔记
activeMq的安装.启动和停止
下载ActiveMq的tar安装包, 解压到响应目录下, 使用bin目录下的./activemq start启动, ./activemq stop停止
activemq和spring-boot整合
配置类
@Configuration
@EnableJms //启动消息队列组件
public class ActivemqConfig {
/**
* 使用队列
*/
@Bean
public Queue queue() {
return new ActiveMQQueue("activemq-queue");
}
/**
* activemq策略配置
*
* 问题: 消息碰撞是什么?
*/
@Bean
public RedeliveryPolicy redeliveryPolicy() {
RedeliveryPolicy policy = new RedeliveryPolicy();
//是否在每次尝试发送失败后, 增加下次发送等待时间
policy.setUseExponentialBackOff(true);
//设置重发次数, 默认为6次
policy.setMaximumRedeliveries(6);
// 重新发送时间间隔
policy.setInitialRedeliveryDelay(1);
// 第一次发送失败后, 重新发送之前等待500毫秒, 再次失败500 * 2
policy.setBackOffMultiplier(2);
//设置重发最大拖延时间-1 表示没有拖延只有UseExponentialBackOff(true)为true时生效
policy.setMaximumRedeliveryDelay(-1);
return policy;
}
/**
* 设置连接工厂
* @param url activemq服务路径
*/
@Bean
public ActiveMQConnectionFactory activeMQConnectionFactory(@Value("${spring.activemq.broker-url}") String url) {
ActiveMQConnectionFactory connectionFactory =
new ActiveMQConnectionFactory("admin", "admin", url);
connectionFactory.setRedeliveryPolicy(redeliveryPolicy());
//表示使用异步投递
connectionFactory.setUseAsyncSend(true);
return connectionFactory;
}
/**
* 设置消息发送模板(queue点对点方式)
*/
@Bean
public JmsTemplate jmsQueueTemplate(ActiveMQConnectionFactory activeMQConnectionFactory) {
JmsTemplate jmsTemplate = new JmsTemplate(activeMQConnectionFactory);
// true使用topic广播模式, false使用queue点对点模式
jmsTemplate.setPubSubDomain(false);
// 设置要发送的队列
jmsTemplate.setDefaultDestination(queue());
// 设置消息持久化, true时才能配置持久化
jmsTemplate.setExplicitQosEnabled(true);
// 将消息持久化到磁盘
jmsTemplate.setDeliveryMode(DeliveryMode.PERSISTENT);
// 是否开启事务, false不开启(手动提交), true开启事务(自动提交)
jmsTemplate.setSessionTransacted(false);
// 客户端手动签收(手动签收只有在不使用事务时才生效)
jmsTemplate.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
return jmsTemplate;
}
/**
* 消息监听器, 只在consumer端配置(这里因为producer和consumer在一个项目中)
*/
@Bean
public DefaultJmsListenerContainerFactory jmsQueueListenerContainerFactory(ActiveMQConnectionFactory activeMQConnectionFactory) {
DefaultJmsListenerContainerFactory factory =new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(activeMQConnectionFactory);
// 设置连接数
factory.setConcurrency("1-10");
// 重连间隔时间
factory.setRecoveryInterval(1000L);
// 客户端签收模式
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
return factory;
}
}
消费者
@Component
public class Consumer {
private final static Logger logger = LoggerFactory.getLogger(Consumer.class);
@JmsListener(destination = "queue1", containerFactory = "jmsQueueListener")
public void receiveQueue(final TextMessage text, Session session)throws JMSException {
try {
logger.debug("Consumer收到的报文为:" + text.getText());
text.acknowledge();// 使用手动签收模式,需要手动的调用,如果不在catch中调用session.recover()消息只会在重启服务后重发
} catch (Exception e) {
session.recover();// 此不可省略 重发信息使用
}
}
}
生产者(不同的设置, 生产者和消费者要进行签收或者提交操作)
@Component
public class Producter {
@Autowired("..")//这里根据消息发布类型不同注入
private JmsTemplate jmsTemplate;
@Autowired
private Queue queue;
@Autowired
private Topic topic;
//发送queue类型消息
public void sendQueueMsg(String msg){
jmsTemplate.convertAndSend(queue, msg);
}
//发送topic类型消息
public void sendTopicMsg(String msg){
jmsTemplate.convertAndSend(topic, msg);
}
}
延时投递的实现(其余高级特性实现方式类似)
broker配置文件schedulerSupport修改为true
@Service
public class Producer {
public static final Destination DEFAULT_QUEUE = new ActiveMQQueue("delay.queue");
@Autowired
private JmsMessagingTemplate template;
/**
* 延时发送
*
* @param destination 发送的队列
* @param data 发送的消息
* @param time 延迟时间
*/
public void delaySend(Destination destination, T data, Long time) {
Connection connection = null;
Session session = null;
MessageProducer producer = null;
// 获取连接工厂
ConnectionFactory connectionFactory = template.getConnectionFactory();
try {
// 获取连接
connection = connectionFactory.createConnection();
connection.start();
// 获取session,true开启事务,false关闭事务
session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
// 创建一个消息队列
producer = session.createProducer(destination);
producer.setDeliveryMode(JmsProperties.DeliveryMode.PERSISTENT.getValue());
ObjectMessage message = session.createObjectMessage(data);
//设置延迟时间
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time);
// 发送消息
producer.send(message);
log.info("发送消息:{}", data);
session.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (producer != null) {
producer.close();
}
if (session != null) {
session.close();
}
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
ActiveMQ消息异步投递
默认是异步发送消息, 这种消息效率更高, 但是会出现消息丢失, 但是有以下情况会发送同步消息
1.指定使用同步发送消息
2.在没有事务的前提下发送持久化消息
如何确保消息发送成功
需要接收回调
// 创建一个消息队列
ActiveMqMessageProducer producer = (ActiveMqMessageProducer)session.createProducer(destination);
ObjectMessage message = session.createObjectMessage(data);
// 发送消息
producer.send(message, new AsyncCallback() {
...
});
消息的重试机制
1. 什么情况下会导致消息的重试
. 客户端在使用事务的前提下, rollBack()或者没有commit()消息;
. 未使用事务的前提下, 使用ACKNOWLEDGE模式, 进行了session.recover()
2. 重试多少次, 每次间隔
默认是6次, 间隔为1s
3. 超过重发的次数, 消息会被放入死信队列中
死信队列的处理
可以通过individualDeadLetterStrategy来设置各自的死信队列, 也可以设置过期
保证消息的幂等性
可以根据messageId来做校验, 可以使用redis来做