AcitiveMQ学习总结——相关使用

ActiveMQ学习总结

ActiveMQ下载地址:ActiveMQ

一、Windows环境下安装ActiveMQ并启动

1.直接解压压缩包

2.进入目录直接启动
在这里插入图片描述
3.访问http://127.0.0.1:8161/并登录(账号密码在conf文件夹中的users.properties中)

二、Linux环境下安装ActiveMq并启动

1.将apache-activemq-5.16.0-bin.tar.gz传到Linux下

2.解压

  • tar -zxvf apache-activemq-5.16.0-bin.tar.gz

3.复制到/usr/local/activemq下(可不复制)

  • cp -a apache-activemq-5.16.0 /usr/local/activemq

4.进入bin目录并启动

  • cd /usr/local/cativemq/bin
  • ./activemq start

5.查看是否启动成功

  • ps -ef|grep activemq
root     13410     1 21 16:53 pts/0    00:00:06 /usr/local/software/jdk1.8.0_171/bin/java -Xms64M -Xmx1G -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config=/usr/local/activem//conf/login.config -Dcom.sun.management.jmxremote -Djava.awt.headless=true -Djava.io.tmpdir=/usr/local/activemq//tmp -Dactivemq.classpath=/usr/local/activemq//conf:/usr/local/activemq//../lib/: -Dactivemq.home=/usr/local/activemq/ -Dactivemq.base=/usr/local/activemq/ -Dactivemq.conf=/usr/local/activemq//conf -Dactivemq.data=/usr/local/activemq//data -jar /usr/local/activemq//bin/activemq.jar start
root     13451 13280  0 16:54 pts/0    00:00:00 grep --color=auto activemq

6.将端口开放8161和61616

7.(重点)如果安全组和防火墙都放行了8161和61616还是无法访问就进入conf文件中的jetty.xml将127.0.0.1修改为0.0.0.0并重启activemq

三、ActiveMQ的使用

1.创建Maven项目

在这里插入图片描述

2.配置POM

<properties>
        <activemq.version>5.15.5</activemq.version>
        <slf4j.version>1.7.25</slf4j.version>
        <lombok.version>1.16.20</lombok.version>
    </properties>

    <dependencies>

<!--        ActiveMQ配置-->
        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-all</artifactId>
            <version>${activemq.version}</version>
        </dependency>

<!--        slf4j通用配置-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>${slf4j.version}</version>
        </dependency>

<!--        lombok配置-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>

3.点对点模式(Queue模式队列)

3.1 生产者发送消息(默认是持久)
  • 创建ConnectionFactory对象,需要指定服务端IP及端口号
  • 使用ConnectionFactory对象创建一个Connection对象
  • 开启连接,调用Connection对象的start方法
  • 使用Connection对象创建一个Session对象(是否开启事务,接收者的签收状态-自动签收)
  • 使用Session对象创建一个Destination对象(topic/queue),此处创建一个Queue对象
  • 使用Session对象创建一个Producer对象
  • 创建一个Messageu对象,创建一个TextMessage对象
  • 使用Producer对象发送消息
  • 关闭资源
public class TestQueueProducer {

    private static String BROKER_URL = "tcp://**.**.**.**:61616";
    private static String QUEUE_NAME="QUEUE-HELLO";

    public static void main(String[] args) throws JMSException {
        ConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL);
        Connection connection = factory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(QUEUE_NAME);
        MessageProducer producer = session.createProducer(queue);
//      TextMessage message = new ActiveMQTextMessage();
        TextMessage message = session.createTextMessage();
        message.setText("hello");
        producer.send(message);
        producer.close();
        session.close();
        connection.close();
        System.out.println("消息发送成功!");
    }
}

异步生产:

public class TestQueueProducerSync {

    private static String BROKER_URL = "tcp://**.**.**.**:61616";
    private static String QUEUE_NAME="QUEUE-HELLO";

    public static void main(String[] args) throws JMSException {
        ConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL);
        Connection connection = factory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(QUEUE_NAME);
        MessageProducer producer = session.createProducer(queue);
        for (int i = 1;i<=10;i++){
            TextMessage message = session.createTextMessage();
            message.setText("hello"+i);
            producer.send(message);
        }
        producer.close();
        session.close();
        connection.close();
        System.out.println("消息发送成功!");
    }
3.2 消费者消费消息
  • 创建ConnectionFactory对象,需要指定服务端IP及端口号
  • 使用ConnectionFactory对象创建一个Connection对象
  • 开启连接,调用Connection对象的start方法
  • 使用Connection对象创建一个Session对象(是否开启事务,接收者的签收状态-自动签收)
  • 使用Session对象创建一个Destination对象(topic/queue),此处创建一个Queue对象
  • 使用Session对象创建一个Consumer对象
  • 监听消息
  • 关闭资源
public class TestQueueConsumer {
    private static String BROKER_URL = "tcp://**.**.**.**:61616";
    private static String QUEUE_NAME="QUEUE-HELLO";

    public static void main(String[] args) throws JMSException {
        ConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL);
        Connection connection = factory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(QUEUE_NAME);
        MessageConsumer consumer = session.createConsumer(queue);
        Message message = consumer.receive(2000);
        if (message instanceof TextMessage){
            TextMessage text= (TextMessage) message;
            System.out.println("接收到了消息,消息内容为:"+text.getText());
        }
        session.close();
        connection.close();
        System.out.println("消息接收成功!");
    }
}

异步消费:

public class TestQueueConsumerSync {
    private static String BROKER_URL = "tcp://**.**.**.**:61616";
    private static String QUEUE_NAME="QUEUE-HELLO";

    public static void main(String[] args) throws JMSException, IOException {
        ConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL);
        Connection connection = factory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(QUEUE_NAME);
        MessageConsumer consumer = session.createConsumer(queue);
        //异步使用setMessageListener
        consumer.setMessageListener(new MessageListener() {
            public void onMessage(Message message) {
                if (message instanceof TextMessage){
                    try {
                        System.out.println("接收到了消息:"+((TextMessage) message).getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        System.in.read();
        session.close();
        connection.close();
        System.out.println("消息接收成功!");
    }
}
3.3 三大消费情况
  1. 先生产,只启动1号消费者。1号消费者能消费到消息吗--------->可以
  2. 先生产,先启动1号消费者再启动2号消费者。2号消费者还能消费消息吗?-------->不可以,全部被1号消费完了
  3. 先启动2个消费者,再生产10条消息。消费情况如何?-------->一人一半,轮询消费

4.发布/订阅模式(Topic模式队列)

先启动消费者再启动生产者,不然发送的就是废消息(先关注订阅号才能收到消息)

1.生产消息
public class TestTopicProducer {
    public static void main(String[] args) throws JMSException {
        String brokerURL = "tcp://**.**.**.**:61616";
        String topicName = "topicName";
        ConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
        Connection connection = factory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //topic
        Topic topic = session.createTopic(topicName);
        MessageProducer producer = session.createProducer(topic);
        for (int i=1;i<=10;i++){
            TextMessage textMessage = session.createTextMessage("topic-message" + i);
            producer.send(textMessage);
        }
        producer.close();
        session.close();
        connection.close();
        System.out.println("主题发送完成!");

    }
}
2.消费消息

活动非持久化(默认)

public class TestTopicConsumer {
    public static void main(String[] args) throws JMSException, IOException {
        String brokerURL = "tcp://**.**.**.**:61616";
        ConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
        Connection connection = factory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        String topicName = "topicName";
        Topic topic = session.createTopic(topicName);
        System.out.println("2号消费者");
        MessageConsumer consumer = session.createConsumer(topic);
        consumer.setMessageListener(new MessageListener() {
            @SneakyThrows
            public void onMessage(Message message) {
                if (message instanceof TextMessage){
                    System.out.println("接收到消息:"+((TextMessage) message).getText());
                }
            }
        });
        System.in.read();
        session.close();
        connection.close();
        System.out.println("主题发送完成!");

    }
}

活动持久化(设置ClientID)

public class TestTopicConsumerDurable {
    public static void main(String[] args) throws JMSException, IOException {
        String brokerURL = "tcp://**.**.**.**:61616";
        ConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
        Connection connection = factory.createConnection();
        connection.setClientID("陈少磊"); //设置订阅者的ID
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        String topicName = "topicName";
        Topic topic = session.createTopic(topicName);
        // 创建一个持久的主题订阅者
        TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic, "remark");
        System.out.println("陈少磊消费者");
        topicSubscriber.setMessageListener(new MessageListener() {
            @SneakyThrows
            public void onMessage(Message message) {
                if (message instanceof TextMessage){
                    System.out.println("接收到消息:"+((TextMessage) message).getText());
                }
            }
        });
        System.in.read();
        session.close();
        connection.close();
        System.out.println("主题发送完成!");

    }
}

在这里插入图片描述

5.点对点与发布/订阅模式的比较

Topic模式队列Queue模式队列
工作模式“订阅-发布”模式,如果当前没有订阅者,消息将会被丢弃。如果有多个订阅者,那么这些订阅者都会接收到消息“负载均衡”模式,如果当前没有消费者,消息也不会被丢弃;如果有多个消费者,那么一条消息也只会发送给启动一个消费者,并且要求消费者ack信息
有无状态无状态Queue数据默认回在MQ服务器上以文件形式保存,比如ActiveMQ一般保存在$AMQ_HOME\data\kr-store\data下,也可以配置成DB存储。
传递性能如果没有订阅者,消息会被丢弃消息不会被丢弃
处理效率由于消息要按照订阅者的数量进行复制,所以处理性能回随着订阅者的增加而明显降低,并且还要结合不同消息协议自身的性能差异由于一条消息只发送给一个消费者,所以就算消费者再多,性能也不会明显降低,当然不同消息协议的具体性能也有差异的。

6.JMS Messager

6.1 消息头

JMS消息头包含了许多字段,它们是消息发送后由JMS提供者或消息发送者产生,用来表示消息、设置优先权和失效时间等等,并且为消息确定路由。

  • JMSDesination:消息发送的目的地。只要指Queue和Topic;
  • JMSDeliveyMode:消息的持久模式和非持久模式;
  • JMSExpiration:消息的过期设置,默认为永不过期;
  • JMSPriority:消息优先级,0-9十个级别:0-4为普通级别、5-9为加急消息;
  • JMSMessageID:唯一识别每个消息的表示,由MQ产生。
  • JMSCorrelationID:通常用来关联多个Message。
  • JMSRedelivered:如果这个值为true,表示消息是被重新发送了。
  • JMSReplyTo:有时消息生产者希望消费者回复一个消息,JMSReplyTo为一个Destination,表示需要回复的目的地。当然消费者可以不理会它。
  • JMSTimestamp:当调用send()方法的时候,JMSTimestamp会被自动设置为当前时间戳。
long timestamp = message.getJMSTimestamp();
  • JMSType:表示消息体的结构,和JMS提供者有关。
属性名描述类型默认值设置者
JMSDesination发送消息目的地Destination生产者set进去的send
JMSDeliveyMode是否要持久化intDeliveryMode.PERSISTENT(持久)send
JMSExpiration用户定义long0send
JMSPriority0-9int4send
JMSMessageID消息唯一标示符Stringuniquesend
JMSCorrelationID用户定义Stringnullclient
JMSRedelivered是否重新传递booleanfalseprovider
JMSReplyTo用户定义Destinationnullclient
JMSTimestamp毫秒long消息发送时间send
JMSType用户定义String“”client
6.2 消息体

封装具体的消息数据,5种消息体格式,发送和接受的消息必须一致对应
在这里插入图片描述

  • TextMessage: 一个字符串对象

  • StreamMessage: Java原始的数据流

  • MapMessage: 键值对

  • BytesMessage:一个字节的数据流

  • ObjectMessage: 一个序列化的Java对象,需放行所有包的安全

ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(brokerURL);
// 放行所有包的安全检查
factory.setTrustAllPackages(true);
6.3 消息属性

由消息发送者产生,用来添加消息头以外的附加信息。

  • 应用程序设置和添加的属性。
message.setStringProperty("username",username);
  • JMS定义的属性。
  • JMS供应商特定的属性

7. ActiveMQ签收

生产者偏向事务,消费者偏向签收。

7.1 非事务模式下签收
  • 生产者签收设置为自动,消费者签收设置为自动---->正常

  • 生产者签收设置为自动,消费者签收设置为手动,未ACK->重复消费

  • 生产者签收设置为自动,消费者签收设置为手动,已ACK->正常

  • 生产者签收设置为手动,消费者签收设置为自动->正常

  • 生产者签收设置为手动,消费者签收设置为手动,未ACK---->重复消费

  • 生产者签收设置为手动,消费者签收设置为手动,已ACK ----->正常

总结:消费者需自动就正常,消费者手动需ACK就正常

7.2 有事务模式下签收(都开启了事务)

如果生产者设置有事务但不提交,消息发送不出去;必须在send之后调用session.commit();

producer.send(message);
session.commit();
  • 生产者签收设置为自动,消费者签收设置为自动,已提交->正常

  • 生产者签收设置为自动,消费者签收设置为手动,已提交,未ACK->正常

  • 生产者签收设置为自动,消费者签收设置为自动,未提交->重复消费

  • 生产者签收设置为自动,消费者签收设置为手动,未提交,已ACK->重复消费

  • 生产者签收设置为手动,消费者签收设置为自动,已提交-> 正常

  • 生产者签收设置为手动,消费者签收设置为自动,未提交 -> 重复消费

  • 生产者签收设置为手动,消费者签收设置为自动末,未提交,未ACK -> 重复消费

  • 生产者签收设置为手动,消费者签收设置为自动,未提交,已ACK -> 重复消费

  • 生产者签收设置为手动,消费者签收设置为手动,已提交,未ACK->正常

  • 生产者签收设置为手动,消费者签收设置为手动,已提交,已ACK -> 正常

总结:消费者需提交就正常(即提交就是签收)

四、内嵌MQ的使用(Broker)

1.启动Broker
public class EmbedBroker {
    public static void main(String[] args) {
        BrokerService service = new BrokerService();
        service.setUseJmx(true);
        try {
            service.addConnector("tcp://127.0.0.1:61616");
            service.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("内嵌MQ启动成功!");
    }
}
2.启动生产者
public class QueueProducer {
    private static String BROKER_URL = "tcp://127.0.0.1:61616";
    private static String QUEUE_NAME="QUEUE-HELLO";

    public static void main(String[] args) throws JMSException {
        ConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL);
        Connection connection = factory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue(QUEUE_NAME);
        MessageProducer producer = session.createProducer(queue);
        TextMessage message = session.createTextMessage();
        message.setText("hello");
        message.setStringProperty("flag","??/");
        producer.send(message);
        producer.close();
        session.close();
        connection.close();
        System.out.println("消息发送成功!");
    }
}
3.启动消费者
public class QueueConsumer {
    private static String BROKER_URL = "tcp://127.0.0.1:61616";
    private static String QUEUE_NAME="QUEUE-HELLO";

    public static void main(String[] args) throws JMSException {
        ConnectionFactory factory = new ActiveMQConnectionFactory(BROKER_URL);
        Connection connection = factory.createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
        Queue queue = session.createQueue(QUEUE_NAME);
        MessageConsumer consumer = session.createConsumer(queue);
        Message message = consumer.receive(2000);
        if (message instanceof TextMessage){
            TextMessage text= (TextMessage) message;
            message.acknowledge();
            System.out.println("接收到了消息,消息内容为:"+text.getText()+" "+message.getStringProperty("flag"));
        }
        session.close();
        connection.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值