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
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}" 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 <T extends Serializable> 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来做

红番茄
7 声望2 粉丝

引用和评论

0 条评论