Table of Contents

一、linux 安装activemq及应用

二、JMS

一组成:

二 消息可靠性 : (持久性  ,事务,  签收)

 1 persisent 持久性:messageProducer.setDeliverymodel(DeliveryModel.NOO_PERSISENT);//非持久化

  2 事务

 3 acknowledge 签收

总结:

四、spring整合activemq

五、SpringBoot整合Activemq

1 队列:

2:发布订阅

 topic生产者:

topic消费者:

六、AcitveMQ传输协议 

tcp语法:tcp://hostname:port?key=value

 NIO 传输人协议:

七 activemq持久化

 JDBC持久化JDBC persistence.演示

jdbc with  journal  演示

八、ActiveMQ集群

九、高级特性



一、linux 安装activemq及应用

https://activemq.apache.org/官网下载apache-activemq-5.15.9-bin.tar.gz  用xftp上传到/opt目录解压在bin目录中启动./activemq start   ,前提是需要对应jdk版本(我安装是对应需要jdk1.8)

查看启动:
启动 bin下面的命令
./activemq start

默认后台端口61616 前台端口8161
查看是否启动三种方式
1  netstat -anp |grep 61616
2  ps -er | grep activemq | grep -v grep
3  lsof -i:61616

 

activemq 日志定时清理_System

 

两个模式:queue和topic

activemq 日志定时清理_activemq 日志定时清理_02

两个模式的差异

activemq 日志定时清理_System_03

 

 

 

javaee

activemq 日志定时清理_spring_04

JMS

activemq 日志定时清理_持久化_05

二、JMS

一组成:

JMS    组成结构和特点
provide 服务器
produce 生产者
consumer 消费者
message :消息头,消息体,消息属性

JMS message
消息头:几个重要的设置
JMSDestination 目的地:发送消息的目的地主要指Queue和Topic
JMSDeliveryModel  持久和非持久
JMSExpiration  消息过期设置
JMSPriority    消息优先级
JMSMessageID   消息唯一标志id:唯一识别每个消息的标志由mq产生

activemq 日志定时清理_System_06

 

activemq 日志定时清理_spring_07

activemq 日志定时清理_持久化_08

消息体 :封装具体的消息数据
5种消息体格式:
TextMessage 普通的字符串包含一个String
MapMessage  一个Map类型消息,key是String 而值是java基本类型
BytesMessage  二进制数组消息,包含一个byte[]
StreamMessage  java数据流消息,用标准的流操作来顺序填充和读取
ObjectMess age   对象消息,包含一个可序列化的java对象
发送和接收消息体类型必须一致对应
 

消息属性
如果需要除消息头字段以外的值,那么可以使用消息属性
识别/去重/重点标注等操作非常有用的方法
是一对kv对:如 textMessage.setStringProperty("c01","vip");
 

二 消息可靠性 : (持久性  ,事务,  签收)

 1 persisent 持久性:messageProducer.setDeliverymodel(DeliveryModel.NOO_PERSISENT);//非持久化

       DeliveryModel.PERSISENT持久化 默认策略就是持久化
     持久化topic:一定要先运行一次消费者等于是想mq注册,类似订阅了这个主题,然后再运行生产者发送消息
       此时无论消费者是否在线都会接收到消息,不在线的话下次连接时候会把没有接收过的消息都接收回来。

activemq 日志定时清理_持久化_09


       队列:1 非持久性演示:当服务器宕机 ,消息依然存在

                  2 持久性演示:当服务器宕机,消息依然存在

                 3 队列默认策略就是持久化

    topic:持久化演示

             一定先运行一次消费者,等于向mq注册,类似我们订阅了这个主题,然后再运行生产者发送消息
             此时,无论消费者是否在线,都会接受到,不在线的话,下次连接时候会把没有接收的消息都接收下来
       

----订阅者 
 private static final String URL_BROKER = "tcp://192.168.163.131:61616";
    private static final String TOPIC_NAME = "topic_persisent";
    public static void main(String[] args) throws JMSException, IOException {
        System.out.println("我是余斌号消费者");
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(URL_BROKER);
        Connection connection = activeMQConnectionFactory.createConnection();
        //指定客户端是哪个订阅了
        connection.setClientID("余斌");

        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //创建目的地tipic
        Topic topic = session.createTopic(TOPIC_NAME);

        //创建持久的订阅者 Subscribers  是订阅哪个主题topic
        TopicSubscriber durableSubscriber = session.createDurableSubscriber(topic, "描述信息。。。");

        connection.start();

        //主题的订阅者接收
        Message message = durableSubscriber.receive();
        while (message != null) {
            TextMessage textMessage = (TextMessage) message;
            System.out.println("接收持久化的topic 消息:"+textMessage.getText());
            message =durableSubscriber.receive(3000L);
        }


        session.close();
        connection.close();
        System.out.println("消息接收完毕!");

--事务偏生产者,签收偏消费者

  2 事务

      Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
    
    如果是false:只要执行send就进入到队列中去,关闭事务,那么第二个签收参数设置需要有效
    如果是true,先执行send在执行commit,消息才被真正提交到队列中,消息需要批量发送需要缓冲区处理

  生产者--------如果是false 则send的时候就提交成功到目的地,如果是true,一定需要提交commit,出错可以回滚rollback,如果没有commit那么消息就没有发送到目的地。

消费者

 3 acknowledge 签收

activemq 日志定时清理_activemq_10

 

非事务下的签收: 
    1 自动签收(默认)
    2 手动签署 :需要显示的调用acknowledge方法,如 textMessage.acknowledge();
    3 可重复签收:了解即可

事务下的签收
    生产事务开始,只有commit后才能将全部消费变为已消费
    当一个事务被成功提交则消息被自动签收,如果事务回滚,则消息会被再次传送,
    
    事务与签收的关系:事务比签收更大,只要是开始事务,不管有没有显示调用acknowledge方法,只要提交就默认是自动签收
    如果开启事务但是没有commit调用,即使写了acknowledge方法签收也不会成功。
    
非事务会话中,消息何时被确认取决于创建会话时候的应答模式(acknowledgement model),如果自动签收就自动,如果手动签收就需要调用textMessage.acknowledge();
     

总结:

队列

activemq 日志定时清理_System_11

topic 

activemq 日志定时清理_activemq 日志定时清理_12

 非持久订阅

private static final String URL_BROKER = "tcp://192.168.163.131:61616";
    private static final String TOPIC_NAME = "topic_01";
    public static void main(String[] args) throws JMSException, IOException {
        System.out.println("我是1号消费者");
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(URL_BROKER);
        Connection connection = activeMQConnectionFactory.createConnection();

        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        Topic topic = session.createTopic(TOPIC_NAME);

        MessageConsumer consumer = session.createConsumer(topic);

        consumer.setMessageListener(message -> {
            if(null != message && message instanceof TextMessage) {
                TextMessage textMessage = (TextMessage) message;
                try {
                    System.out.println("接收消息:"+textMessage.getText());
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
            if(null != message && message instanceof MapMessage) {
            MapMessage mapMessage = (MapMessage) message;
            try {
                String k1 = mapMessage.getString("k1");
                System.out.println("接收消息:"+k1);

            } catch (JMSException e) {
                e.printStackTrace();
            }
            }
        });
        System.in.read();
        consumer.close();
        session.close();
        connection.close();
        System.out.println("消息接收完毕!");
    }

activemq 日志定时清理_activemq 日志定时清理_13

 持久订阅

private static final String URL_BROKER = "tcp://192.168.163.131:61616";
    private static final String TOPIC_NAME = "topic_persisent";
    public static void main(String[] args) throws JMSException, IOException {
        System.out.println("我是余斌号消费者");
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(URL_BROKER);
        Connection connection = activeMQConnectionFactory.createConnection();
        //指定客户端是哪个订阅了
        connection.setClientID("余斌");

        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //创建目的地tipic
        Topic topic = session.createTopic(TOPIC_NAME);

        //创建持久的订阅者 Subscribers  是订阅哪个主题topic
        TopicSubscriber durableSubscriber = session.createDurableSubscriber(topic, "描述信息。。。");

        connection.start();

        //主题的订阅者接收
        Message message = durableSubscriber.receive();
        while (message != null) {
            TextMessage textMessage = (TextMessage) message;
            System.out.println("接收持久化的topic 消息:"+textMessage.getText());
            message =durableSubscriber.receive(3000L);
        }


        session.close();
        connection.close();
        System.out.println("消息接收完毕!");



    }

 

activemq 日志定时清理_activemq 日志定时清理_14

 必须签收用持久订阅,当丢失消息能够被容忍,则用非持久订阅

 

三、linux启动不同的配置文件(类似redis)

./activemq start xbean:file:/myactivemq/conf/activemq02.xml

activemq 日志定时清理_activemq 日志定时清理_15

启动本地idea中的broker

 

public static void main(String[] args) throws Exception {
        BrokerService brokerService = new BrokerService();
        brokerService.setUseJmx(true);
        brokerService.addConnector("tcp://localhost:61616");
        brokerService.start();
    }

G:\360Downloads\workspace201907\activemq>jps -l
3280 com.yubin.cn.activemq.Embed.EmbedBroker
6464 sun.tools.jps.Jps
1044 org.jetbrains.jps.cmdline.Launcher
5304 org.jetbrains.idea.maven.server.RemoteMavenServer
4284

G:\360Downloads\workspace201907\activemq>
 

 

四、spring整合activemq

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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/context
       http://www.springframework.org/schema/context/spring-context.xsd">


    <context:component-scan base-package="com.yubin.cn.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.163.131:61616"/>
            </bean>
        </property>
        <property name="maxConnections" value="100"></property>
    </bean>
<!--目的地队列-->
    <bean id="destinationQueue" class="org.apache.activemq.command.ActiveMQQueue">
        <constructor-arg index="0" value="spring-active-queue"/>
    </bean>
<!--目的地:topic-->
    <bean id="destinationTopic" class="org.apache.activemq.command.ActiveMQTopic">
        <constructor-arg index="0" value="spring-active-topic"/>
    </bean>

    <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
        <property name="connectionFactory" ref="jmsFactory"/>
        <property name="defaultDestination" ref="destinationTopic"/>
        <property name="messageConverter">
        <bean class="org.springframework.jms.support.converter.SimpleMessageConverter"/>
    </property>
    </bean>


    <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
        <property name="connectionFactory" ref="jmsFactory"></property>
        <property name="destination" ref="destinationTopic"></property>
        <property name="messageListener"  ref="myMessageListener"></property>
    </bean>
</beans>

activemq 日志定时清理_activemq_16

写实现MessageListener一个监听器的类 :可以实现不启动消费者只启动生产者就可以接收到消息(可以监听队列或者topic,只需要配置监听程序中将队列换成topic就可以)

@Component
public class MyMessageListener implements MessageListener {
    @Override
    public void onMessage(Message message) {
        if(null != message && message instanceof TextMessage) {
            TextMessage textMessage = (TextMessage) message;

            try {
                System.out.println("监听到的消息为:"+textMessage.getText());
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    }
}

 

activemq 日志定时清理_activemq_17

五、SpringBoot整合Activemq

1 队列:

activemq 日志定时清理_System_18

//消息生产者主要代码
@Component
public class Queue_Producer {

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @Autowired
    private Queue queue;

    public void producerMsg() {
        jmsMessagingTemplate.convertAndSend(queue,"******:"+UUID.randomUUID().toString().substring(0,6));

    }

    //间隔三秒往Mq推送消息以达到定时发送case,案例
    @Scheduled(fixedDelay= 3000L )
    public void produceMsgScheduled() {
        jmsMessagingTemplate.convertAndSend(queue,"******Scheduled:"+UUID.randomUUID().toString().substring(0,6));
        System.out.println("produceMsgScheduled send ok ");

    }

}

 

 

activemq 日志定时清理_System_19

//消息消费者部分代码
@Component
public class Queue_Consumer {

    @JmsListener(destination = "${myqueue}")
    public void receive(TextMessage textMessage) throws  JMSException {

        System.out.println("监听到的消息为:"+textMessage.getText());

    }
}

 使用jmsMessagetemplete生产消息,使用receive或者配置监听器消费消息。

 

2:发布订阅

activemq 日志定时清理_activemq 日志定时清理_20

activemq 日志定时清理_System_21

 topic生产者:

application.yml配置文件:
server:
  port: 6666
spring:
  activemq:
    broker-url: tcp://192.168.163.131:61616
    user: admin
    password: admin
  jms:
    pub-sub-domain: true


#配置自己的自定义topic
mytopic: springboot-activemq-topic
***********************************************************

配置bean类
@Component
public class confBean {

    @Value("${mytopic}")
    private String topicName;

    @Bean
    public Topic topic() {
        return new ActiveMQTopic(topicName);
    }
}

***********************************************************
定时任务生产消息

@Component
public class Topic_Producer {

    @Autowired
    private JmsMessagingTemplate jmsMessagingTemplate;

    @Autowired
    private Topic topic;

    @Scheduled(fixedDelay = 3000L)
    public void producerTopic() {
        jmsMessagingTemplate.convertAndSend(topic,"主题topic生产消息:"+UUID.randomUUID().toString().substring(0,6));
        System.out.println("topic producer send end");
    }
}

topic消费者:

application.yml配置文件
server:
  port: 5567 #5567
spring:
  activemq:
    broker-url: tcp://192.168.163.131:61616
    user: admin
    password: admin
  jms:
    pub-sub-domain: true



#配置自己的自定义topic
mytopic: springboot-activemq-topic
*************************************************

消费者消费消息:

@Component
public class Topic_Consumer {

    @JmsListener(destination = "${mytopic}")
    public void receiveTopic(TextMessage textMessage) throws JMSException {
        System.out.println("topic消费者接收消息:"+textMessage.getText());
    }
}

六、AcitveMQ传输协议 

activemq 日志定时清理_System_22

activemq 日志定时清理_spring_23

activemq 日志定时清理_持久化_24

tcp语法:tcp://hostname:port?key=value

参数可选的有可以参考官网:https://activemq.apache.org/tcp-transport-reference

activemq 日志定时清理_activemq 日志定时清理_25

 

 NIO 传输人协议:

activemq 日志定时清理_spring_26

activemq 日志定时清理_activemq_27

 

amqp:

activemq 日志定时清理_持久化_28

 

stomp:协议

activemq 日志定时清理_activemq 日志定时清理_29

 

activemq 日志定时清理_System_30

 

SSL协议

activemq 日志定时清理_activemq_31

mqtt协议:

activemq 日志定时清理_activemq 日志定时清理_32

activemq 日志定时清理_持久化_33

ws协议

activemq 日志定时清理_activemq 日志定时清理_34

总结:

activemq 日志定时清理_持久化_35

NIO案例:

消息生产者
public class JmsProduce {

//    private static final String URL_BROKER = "tcp://192.168.163.131:61616";
//    private static final String URL_BROKER = "tcp://localhost:61616";
private static final String URL_BROKER = "nio://192.168.163.131:61618";
    private static final String QUEUE_NAME = "queue1";

    public static void main(String[] args) throws JMSException {
        //创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(URL_BROKER);
        //创建连接
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //获取session
        Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
        //声明队列
        Queue queue = session.createQueue(QUEUE_NAME);
        //创建生产者
        MessageProducer producer = session.createProducer(queue);

        for(int i = 1;i<=3;i++) {
            TextMessage textMessage = session.createTextMessage("msg_" + i);
            //设置消息属性
            textMessage.setStringProperty("c01","vip");

            producer.send(textMessage);
        }

        session.commit();
        producer.close();
        session.close();
        connection.close();

        System.out.println("消息发送完毕!");

    }
}
**************************************************

消息消费者
//    private static final String URL_BROKER = "tcp://192.168.163.131:61616";
//    private static final String URL_BROKER = "tcp://localhost:61616";
private static final String URL_BROKER = "nio://192.168.163.131:61618";
    private static final String QUEUE_NAME = "queue1";
    public static void main(String[] args) throws JMSException, IOException {
        System.out.println("我是2号消费者");
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(URL_BROKER);
        Connection connection = activeMQConnectionFactory.createConnection();

        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        Queue queue = session.createQueue(QUEUE_NAME);




        MessageConsumer consumer = session.createConsumer(queue);

        // 方式一  receive
/*
        //订阅者或者接受者MessageConsumer的receive方法来接收消息,receive在能够接收的消息前将一直阻塞
        while(true) {
            //receive可以接收参数,可以指定等待时间,过时不候 Message receive(long timeout)
            TextMessage receive = (TextMessage)consumer.receive();
            if(null != receive) {
                System.out.println("接收消息:"+receive.getText());
            }else {

                break;
            }
        }

        consumer.close();
        session.close();
        connection.close();*/


        //方式二  监听MessageListener
//        异步非阻塞方式(监听onMessage())
//        订阅者或者消息接受者MessageConsumer的setMessageListener(MessageLinstener listener)
//        注册一个消息监听,当消息到达后,系统自动调用监听器的监听方法

        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                if(null != message && message instanceof TextMessage) {
                    TextMessage textMessage = (TextMessage) message;
                    try {
                        System.out.println("接收消息:"+textMessage.getText());
                        System.out.println("接收消息:"+textMessage.getStringProperty("c01"));//获取消息属性
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        System.in.read();
        consumer.close();
        session.close();
        connection.close();
        System.out.println("消息接收完毕!");



    }
}

NIO增强改进

activemq 日志定时清理_activemq_36

activemq 日志定时清理_持久化_37

 

七 activemq持久化

activemq 日志定时清理_System_38

activemq 日志定时清理_activemq 日志定时清理_39

activemq 日志定时清理_spring_40

activemq 日志定时清理_持久化_41

activemq 日志定时清理_activemq 日志定时清理_42

 

activemq 日志定时清理_持久化_43

activemq 日志定时清理_System_44

 

leaelDB:消息存储(了解)

步骤:

jar包:mysql-connector-java-5.1.38.jar

activemq 日志定时清理_持久化_45

activemq 日志定时清理_持久化_46

 JDBC持久化JDBC persistence.演示

activemq 日志定时清理_activemq_47

连接池的配置:

activemq 日志定时清理_System_48

queue队列演示jdbc持久化结果

activemq 日志定时清理_activemq_49

发布订阅topic持久化演示: activemq_acks表中存有信息,msg中消费成功也不会删除,会归档,相当于订阅后可以查看之前的历史

 

activemq 日志定时清理_持久化_50

 

消息jdbc持久化总结和开发坑
 如果queue,在没有消费者消费的情况下将消息保存到activemq_msgs表中。只要有任意一个消费者已经消费过,消费之后这些消息将会立即被删除。
 
 如果是topic,一般先启动消费者订阅然后再生产的情况下会将消息保存到activemq_acks;
 
 坑:
 在配置关系型数据库作为activemq的持久化存储方案时候的坑,
 数据库jar包,记得需要使用相关jar文件放在在activemq安装路径下lib目录下,mysql-jdbc驱动的jar包和对应的数据库连接池jar包
 
 crateTablesOnStartup 属性
 在jadbPersistenceAdapter标签中设置这个属性为true时在第一次启动activemq时候,activemq服务节点会自动创建所需要数据表。启动完成后可以去掉这个属性或者更改为false;
 
 
 下划线坑爹。
 “java.lang.IllegalStateException.BeanFactory.notinitialized or aleardy closed”
 
 这个是因为您在操作系统的机器名中有“_”符号,请修改机器名并且重启后即可解决

 

jdbc with  journal  演示

带高速缓存日志功能的jdbc 持久

activemq 日志定时清理_spring_51

<persistenceFactory>
	<journalPersistenceAdapterFactory 
			journalLogFiles="4"
			journalLogFileSize="32768"
			useJournal="true"
			useQuickJournal="true"
			dataSource="mysql-ds"
			dataDirectory="activemq-data"
 </persistenceFactory>

 

activemq 日志定时清理_System_52

相当于在mysql数据库前面当了一层journal高速缓存,有数据先从journal中存着,如果七八分钟没有消费就慢慢写入mysql,消费也先从journal消费,然后等七八分钟后同步到mysql,将myslq中删除,有点读写分离的样子。

activemq 日志定时清理_System_53

activemq 日志定时清理_spring_54

八、ActiveMQ集群

activemq 日志定时清理_持久化_55

activemq 日志定时清理_activemq_56

 

activemq 日志定时清理_持久化_57

 

 集群原理图

activemq 日志定时清理_System_58

 

九、高级特性

一  异步投递

:指定同步或者非事务情况下发送持久化消息两种情况下是同步的,其他都是异步的

activemq 日志定时清理_activemq 日志定时清理_59

官方配置:三种方式

activemq 日志定时清理_activemq 日志定时清理_60

 

异步发送如何确定发送成功 :正确的异步发送是需要接收回调的

 ActiveMQMessageProduce 生产者回调方法确定消息发送成功

public class JmsProduce_mianshi_async {

    private static final String URL_BROKER = "tcp://192.168.163.131:61616";

    private static final String QUEUE_NAME = "queue_async";


    public static void main(String[] args) throws JMSException {
        //创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(URL_BROKER);
        //开启异步投递
        activeMQConnectionFactory.setUseAsyncSend(true);

        //创建连接
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //获取session
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //声明队列
        Queue queue = session.createQueue(QUEUE_NAME);
        //创建生产者
        ActiveMQMessageProducer producer = (ActiveMQMessageProducer) session.createProducer(queue);

        for (int i = 1; i <= 3; i++) {
            TextMessage textMessage = session.createTextMessage("msg_" + i);
            textMessage.setJMSMessageID(UUID.randomUUID().toString() + "order yubin");
            String jmsMessageID = textMessage.getJMSMessageID();
            //设置消息属性
//            textMessage.setStringProperty("c01","vip");

            producer.send(textMessage, new AsyncCallback() {
                //异步发送消息:确认发送成功
                @Override
                public void onSuccess() {
                    System.out.println("messageId:" + jmsMessageID + ".消息发送成功");

                }

                @Override
                public void onException(JMSException exception) {
                    System.out.println("消息发送失败");
                }
            });
        }
        producer.close();
        session.close();
        connection.close();

        System.out.println("消息发送完毕!");

    }
}

 

activemq 日志定时清理_持久化_61

 

二、延迟投递和定时投递

 

activemq 日志定时清理_activemq_62

四大属性:

activemq 日志定时清理_spring_63

延迟投递和定时投递使用案例 :步骤

1 broker服务器开启对延迟和定时的支持schedulerSupport="true"

2 代码编写

activemq 日志定时清理_activemq 日志定时清理_64

private static final String URL_BROKER = "tcp://192.168.163.131:61616";

    private static final String QUEUE_NAME = "delayAndSchedule";
    public static void main(String[] args) throws JMSException {
        //创建连接工厂
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(URL_BROKER);
        //创建连接
        Connection connection = activeMQConnectionFactory.createConnection();
        connection.start();
        //获取session
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //声明队列
        Queue queue = session.createQueue(QUEUE_NAME);
        //创建生产者
        MessageProducer producer = session.createProducer(queue);
        //开启消息持久化
        producer.setDeliveryMode(DeliveryMode.PERSISTENT);
        Long dalay = 3 * 1000L;
        Long period = 4 * 1000L;
        int repeat = 5;
        for(int i = 1;i<=3;i++) {
            TextMessage textMessage = session.createTextMessage("msg_" + i);
            //设置消息属性
            textMessage.setStringProperty("c01","vip");

            textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY,dalay);
            textMessage.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_PERIOD,period);
            textMessage.setIntProperty(ScheduledMessage.AMQ_SCHEDULED_REPEAT,repeat);

            producer.send(textMessage);
        }
        producer.close();
        session.close();
        connection.close();
        System.out.println("消息发送完毕!");

    }

三、Activemq重试机制

https://activemq.apache.org/redelivery-policy

面试题:

具体哪些情况会引起消息重试
说说消息重发时间间隔和重发次数
有毒消息Poison ACK谈谈你的理解

体哪些情况会引起消息重试
答案:
1 client用了transactions并且session调用了rollback()
2 client调用transactions并且调用commit()之前关闭或者没有commit
3 client在client_acknowledeg的传递模式下,sesion调用recover()

说说消息重发时间间隔和重发次数
答案:1秒间隔  重发6次数

有毒的posion ack 谈谈理解
一个消息被redelivedred超过默认做大重发次数(6次)时候,消息端会给ma发送一个posion ack表示这个消息有毒,
告诉break不要再发了,这个时候break会把这个消息放到DLQ(死信队列)
 

重发机制的属性

activemq 日志定时清理_spring_65

 

//手动配置重发机制,不用默认的
RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
redeliveryPolicy.setMaximumRedeliveries(3);
activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);

 

//重试机制,开启事务但是不提交,测试消费六次加第一给 后就不会有消费了

public class JmsConsumer_Redelivery_Policy {
    private static final String URL_BROKER = "tcp://192.168.163.131:61616";

    private static final String QUEUE_NAME = "redleivey_policy";
    public static void main(String[] args) throws JMSException, IOException {
        System.out.println("我是2号消费者");
        ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(URL_BROKER);

        //手动配置重发机制,不用默认的
        RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
        redeliveryPolicy.setMaximumRedeliveries(3);
        activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);

        Connection connection = activeMQConnectionFactory.createConnection();

        connection.start();
        Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);

        Queue queue = session.createQueue(QUEUE_NAME);

        MessageConsumer consumer = session.createConsumer(queue);

        // 方式一  receive
/*
        //订阅者或者接受者MessageConsumer的receive方法来接收消息,receive在能够接收的消息前将一直阻塞
        while(true) {
            //receive可以接收参数,可以指定等待时间,过时不候 Message receive(long timeout)
            TextMessage receive = (TextMessage)consumer.receive();
            if(null != receive) {
                System.out.println("接收消息:"+receive.getText());
            }else {

                break;
            }
        }

        consumer.close();
        session.close();
        connection.close();*/


        //方式二  监听MessageListener
//        异步非阻塞方式(监听onMessage())
//        订阅者或者消息接受者MessageConsumer的setMessageListener(MessageLinstener listener)
//        注册一个消息监听,当消息到达后,系统自动调用监听器的监听方法

        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                if(null != message && message instanceof TextMessage) {
                    TextMessage textMessage = (TextMessage) message;
                    try {
                        System.out.println("接收消息:"+textMessage.getText());
                        System.out.println("接收消息:"+textMessage.getStringProperty("c01"));//获取消息属性
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

//        session.commit();
        System.in.read();
        consumer.close();
        session.close();
        connection.close();
        System.out.println("消息接收完毕!");



    }

重发机制整合在spring中的配置

activemq 日志定时清理_spring_66

 

四、死信队列

activemq 日志定时清理_spring_67

 

死信队列的应用

activemq 日志定时清理_System_68

配置共享和私有的死信队列

shareDeadLetterStrategy,IndvidualDeadLetterStrategy

activemq 日志定时清理_activemq_69

activemq 日志定时清理_activemq 日志定时清理_70

配置自动删除过期消息

 

activemq 日志定时清理_System_71

配置存放非持久性的消息到死信队列

activemq 日志定时清理_activemq_72

 

死信队列配置案例

activemq 日志定时清理_持久化_73

 

 

五、重复消费问题以及幂等性

面试:如何保证消息不被重复消费,幂等性问题的理解

activemq 日志定时清理_spring_74