ActiveMQ : ActiveMQ入门介绍

目录

下载安装

下载 apache-activemq-5.15.2-bin.tar.gz

cd /usr/local/
tar -xzvf apache-activemq-5.15.2-bin.tar.gz
cd /usr/local/apache-activemq-5.15.2/bin
./activemq start

我们可以通过访问 http://localhost:8161/ 进入控制台
这里写图片描述

Queue通信方式

Queue通信方式中只能有一个生产者一个消费者,且消息被消费后出队列.Queue通信方式下如果生产者发送消息时消费者宕机,消费者重启后依然可以收到消息

pom.xml

<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
    <version>5.9.0</version>
</dependency>

生产者 JMSProducer.java

package cn.milo.producer;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

public class JMSProducer {

    private static final String USERNAME = "admin";
    private static final String PASSWORD = "admin";
    private static final String BROKEURL = "tcp://127.0.0.1:61616";
    private static final int SENDNUM = 10;

    public static void main(String[] args) {
        //连接工厂
        ConnectionFactory connectionFactory;
        //连接
        Connection connection = null;
        //会话 接受或者发送消息的线程
        Session session;
        //消息的目的地
        Destination destination;
        //消息生产者
        MessageProducer messageProducer;
        //实例化连接工厂
        connectionFactory = new ActiveMQConnectionFactory(JMSProducer.USERNAME, JMSProducer.PASSWORD, JMSProducer.BROKEURL);

        try {
            //通过连接工厂获取连接
            connection = connectionFactory.createConnection();
            //启动连接
            connection.start();
            //创建session 第一个参数代表开启事务,第二个参数是消息确认方式
            session = connection.createSession(true, Session.CLIENT_ACKNOWLEDGE);
            //创建一个名称为HelloWorld的消息队列
            destination = session.createQueue("HelloWorld");
            //创建消息生产者
            messageProducer = session.createProducer(destination);
            //发送消息
            sendMessage(session, messageProducer);
            //如果不开启事务这里不需要commit
            session.commit();
            session.close();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(connection != null){
                try {
                    connection.close();
                } catch (JMSException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 发送
     */
    public static void sendMessage(Session session,MessageProducer messageProducer) throws Exception{
        for (int i = 0; i < JMSProducer.SENDNUM; i++) {
            //创建一条文本消息
            TextMessage message = session.createTextMessage("ActiveMQ 发送消息" +i);
            System.out.println("发送消息:Activemq 发送消息" + i);
            //通过消息生产者发出消息
            messageProducer.send(message);
        }
    }

}

消费者 JMSConsumer.java

package cn.milo.consumer;

import javax.jms.*;

import org.apache.activemq.ActiveMQConnectionFactory;

public class JMSConsumer {

    private static final String USERNAME = "admin";
    private static final String PASSWORD = "admin";
    private static final String BROKEURL = "tcp://127.0.0.1:61616";

    public static void main(String[] args) {
        //连接工厂
        ConnectionFactory connectionFactory;
        //连接
        Connection connection = null;
        //会话 接受或者发送消息的线程
        final Session session;
        //消息的目的地
        Destination destination;
        //消息的消费者
        MessageConsumer messageConsumer;

        //实例化连接工厂
        connectionFactory = new ActiveMQConnectionFactory(JMSConsumer.USERNAME, JMSConsumer.PASSWORD, JMSConsumer.BROKEURL);

        try {
            //通过连接工厂获取连接
            connection = connectionFactory.createConnection();
            //启动连接
            connection.start();
            //创建session
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            //创建一个连接HelloWorld的消息队列
            destination = session.createQueue("HelloWorld");
            //创建消息消费者
            messageConsumer = session.createConsumer(destination);

            while (true) {
                TextMessage textMessage = (TextMessage) messageConsumer.receive(100000);//同步接受方法
                if(textMessage != null){
                    System.out.println("收到的消息:" + textMessage.getText() + "消息id : " + textMessage.getJMSMessageID() + " testMessage = " + textMessage);
                }else {
                    break;
                }
            }
        } catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

Topic通信方式

Topic通讯方式也叫pub/sub,这个道理很简单就像是我们听收音机一样,你听不听收音机都在播,多少人听收音机都是同样的内容,今晚7点播的内容你晚上9点再过来听就听不到了. 但是有一种特例,如果你的consumer设置了持久化订阅;这种情况下client1这个人如果7点播的时候没听到9点是可以听到的.
这里的收音机就是producer,每位听众就是consumer

生产者 JMSTopicProducer.java

package cn.milo.producer;

import javax.jms.*;

import org.apache.activemq.ActiveMQConnection;

import org.apache.activemq.ActiveMQConnectionFactory;

class JMSTopicProducer {

    public static void main(String[] arg){
        String user = ActiveMQConnection.DEFAULT_USER;
        String password = ActiveMQConnection.DEFAULT_PASSWORD;
        String url = "tcp://localhost:61616";
        String subject = "mq.topic";
        ActiveMQConnectionFactory amcf = new ActiveMQConnectionFactory(user, password, url);
        try {
            Connection conn = amcf.createConnection();
            conn.start();
            Session session = conn.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);
            Destination d = session.createTopic(subject);
            MessageProducer producer = session.createProducer(d);
            for (int i = 0; i <= 20; i++){
                TextMessage message = session.createTextMessage(i+"");
                producer.send(message);
                System.out.println("--发送消息:"  + i);
            }
            session.commit();
            session.close();
            conn.close();
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
}

消费者 JMSTopicConsumer.java

package cn.milo.consumer;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.ActiveMQTopicSubscriber;

import javax.jms.*;


public class JMSTopicConsumer {

    public static void main(String[] args) {
        String USERNAME = "admin";//默认连接用户名
        String PASSWORD = "admin";//默认连接密码
        String BROKEURL = "tcp://localhost:61616";//默认连接地址

        String subject = "mq.topic";
        ConnectionFactory connectionFactory = new ActiveMQConnectionFactory( USERNAME, PASSWORD, BROKEURL);
        Connection connection;
        try{
            connection= connectionFactory.createConnection();
            //创建持久订阅需要设置clientID
            connection.setClientID("client1");
            connection.start();
            final Session session = connection.createSession(Boolean.FALSE,Session.CLIENT_ACKNOWLEDGE);
            Topic topic = session.createTopic(subject);
            // //创建持久订阅
            //ActiveMQTopicSubscriber subscriber = (ActiveMQTopicSubscriber) session.createDurableSubscriber(topic, "Subscriber_name_test");
            //subscriber.setMessageListener();//这里需要使用异步接受
            MessageConsumer consumer = session.createConsumer(topic);
            consumer.setMessageListener(new MessageListener() {
                public void onMessage(Message msg){
                    TextMessage message = (TextMessage) msg;
                    try {
                        System.out.println("--订阅者一收到消息:" +message.getText());
                    }catch(Exception e) {
                        e.printStackTrace();
                    }
                }
            });
//            connection.stop();
//            connection.close();
        }catch (JMSException e) {
            e.printStackTrace();
        }
    }
}

持久化

消费者持久化(接收端持久化)

非持久订阅(non-durable subscription)和持久订阅(durablesubscription)
关于持久化订阅上边Topic已经提到了,持久化订阅也仅对Topic生效.Queue所有消息都是持久化的.而且持久化订阅是consumer的一个属性,换句话讲,这个consumer是持久化的consumer.或者这个consumer不是持久化的.这个大家要理解,不然和下边很容易混淆

消息持久化(发送端持久化)

发送端持久化指的是消息的持久化,换句话讲这个消息是持久化的.应对的场景是这样的.生产者发送了ABCD四个消息,这是消费者都不在线.而且突然activemq服务器宕机,那ABCD四个消息消费者是不是永远都拿不到了.activemq给我们提供了多种持久化方式分别是:JDBC,AMQ,KahaDB和LevelDB,但最终目的都是在activemq宕机的时候消息不会丢失.
当然这里消息持久化还有一种使用场景,消费者消费能力很差,但是生产者生产能力很强,这是activemq很可能在某个时间点有很多没有消费掉的消息,如果此时activemq宕机也会出现消息丢失,同样还是消息持久化机制来解决.

设置消息持久化方法如下:
message.setJMSDeliveryMode(1);
DeliveryMode.NON_PERSISTENT=1:非持久 ;
DeliveryMode.PERSISTENT=2:持久

ACK确认消息

JMS API中约定了Client端可以使用四种ACK_MODE,在javax.jms.Session接口中:

  • AUTO_ACKNOWLEDGE = 1 自动确认
  • CLIENT_ACKNOWLEDGE = 2 客户端手动确认
  • DUPS_OK_ACKNOWLEDGE = 3 自动批量确认
  • SESSION_TRANSACTED = 0 事务提交并确认
  • 此外AcitveMQ补充了一个自定义的ACK_MODE: NDIVIDUAL_ACKNOWLEDGE = 4 单条消息确认

这里的ACK机制是针对消费者的.在生产者设置这个参数我测试是没起什么作用

Session session = conn.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);这个方法第一个参数是是否开启事务,如果开启事务的话第二个参数就会忽略,JMS会自动采用SESSION_TRANSACTED机制.

这里还有一个坑,在spring集成了activemq的时候,配置文件中设置CLIENT_ACKNOWLEDGE这种确认机制的时候并不生效,原因请看spring类org.springframework.jms.listener.AbstractMessageListenerContainer的一段源码:

protected void commitIfNecessary(Session session, Message message) throws JMSException {
        // Commit session or acknowledge message.
        if (session.getTransacted()) {
            // Commit necessary - but avoid commit call within a JTA transaction.
            if (isSessionLocallyTransacted(session)) {
                // Transacted session created by this container -> commit.
                JmsUtils.commitIfNecessary(session);
            }
        }
        else if (message != null && isClientAcknowledge(session)) {
            message.acknowledge();
        }
    }

就是当设置sessionAcknowledgeMode为2时,虽然是客户端手动确认,但是却被spring自动确认了,造成设置无效。这时只需要把sessionAcknowledgeMode的值设置成activemq自定义的类型INDIVIDUAL_ACKNOWLEDGE = 4即可。

Spring集成

大家到百度自己查一下吧,我这里自己写的demo,但是这个demo一直都在瞎改.有兴趣同学可以看一下 https://github.com/shangmingtao/dubbodemo

activemq内容真的很多.上边写的完全是为了学习而学习,所以难免很多地方都漏掉了.大家有好的activemq资料发我一下,感激不尽.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值