首先需要引入activemq的jar包,这里用的是5.14.4版本的

<!-- https://mvnrepository.com/artifact/org.apache.activemq/activemq-all -->
<dependency>
    <groupId>org.apache.activemq</groupId>
    <artifactId>activemq-all</artifactId>
    <version>5.14.4</version>
</dependency>       

P2P消息传递模型:

发送者:

import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.log4j.Logger;

public class FirstSender {

    private static Logger LOGGER = Logger.getLogger(FirstSender.class);
    private static final int SEND_NUMBER = 100;

    public static void main(String[] args) {
        ActiveMQConnectionFactory connectionFactory = null;
        QueueConnection connection = null;
        QueueSession session = null;
        Queue queue = null;
        QueueSender sender = null;
        TextMessage message = null;
        try {
            connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,
                    ActiveMQConnection.DEFAULT_PASSWORD, "tcp://192.168.220.128:61616");
            connection = connectionFactory.createQueueConnection();
            connection.start();
            session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
            queue = session.createQueue("firstQueue");
            sender = session.createSender(queue);       //默认是持久化模式的
            sender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            for (int i = 0; i < SEND_NUMBER; i++) {
                message = session.createTextMessage("你好吗!!");
                sender.send(message);
            }
        } catch (JMSException e) {
            LOGGER.error("向消息队列发送消息失败", e);
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    LOGGER.error("connection关闭失败", e);
                }
            }
        }
    }
}

本例中创建的是非事务性的session,如果创建的是事务性的session的话(第一个参数传true),那么在sender.send()方法之后,还需要调用session.commit()方法,否则事务不会提交,消息不会被丢到消息队列中去。此外,send()方法默认是同步的,如果想要异步发送,则需要调用ConnectionFactory对象的setUseAsyncSend(boolean useAsyncSend)方法或者setAlwaysSyncSend(boolean alwaysSyncSend)方法。

接收者:

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.log4j.Logger;

public class FirstReceiver {
    private static Logger LOGGER = Logger.getLogger(FirstReceiver.class);

    public static void main(String[] args) {
        ActiveMQConnectionFactory connectionFactory = null;
        QueueConnection connection = null;
        QueueSession session = null;
        Queue queue = null;
        QueueReceiver receiver = null;
        try {
            connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,
                    ActiveMQConnection.DEFAULT_PASSWORD, "tcp://192.168.220.128:61616");
            connection = connectionFactory.createQueueConnection();
            connection.start();
            session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
            queue = session.createQueue("firstQueue");
            receiver = session.createReceiver(queue);
            receiver.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    try {
                        TextMessage text = (TextMessage) message;
                        LOGGER.info(text.getText());
                    } catch (InterruptedException e) {
                        LOGGER.error("线程休眠异常", e);
                    } catch (JMSException e) {
                        LOGGER.error("接收消息异常", e);
                    }
                }
            });
        } catch (Exception e) {
            LOGGER.error("接收消息失败", e);
        }
    }
}

在本例中,接收者接收消息的方式采用的是异步的方式,即注册了一个监听器,即使队列中没有消息可以消费了,代码还会继续往下走,不会在这里阻塞的。实际上,正常情况下都应该用此异步方式来接收消息。

jms规范提供了javax.jms.QueueBrowser接口来看队列中的元素,activemq对应的实现类是org.apache.activemq.ActiveMQQueueBrowser,这个类实现了QueueBrowser和Enumeration接口。QueueBrowser对象可以通过Session对象的createBrowser(Queue queue)方法得到,利用其Enumeration getEnumeration()方法、boolean hasMoreElements()方法及Object nextElement()方法可以查看队列中的元素。

Pub/Sub消息传递模型:

发布者:

import javax.jms.JMSException;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicPublisher;
import javax.jms.TopicSession;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.log4j.Logger;

public class FirstPublisher {

    private static Logger LOGGER = Logger.getLogger(FirstPublisher.class);
    private static final int PUBLISH_NUMBER = 100;

    public static void main(String[] args) {
        ActiveMQConnectionFactory connectionFactory = null;
        TopicConnection connection = null;
        TopicSession session = null;
        Topic topic = null;
        TopicPublisher publisher = null;
        try {
            connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,
                    ActiveMQConnection.DEFAULT_PASSWORD, "tcp://192.168.220.128:61616");
            connection = connectionFactory.createTopicConnection();
            connection.start();
            session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
            topic = session.createTopic("firstTopic");
            publisher = session.createPublisher(topic);
            for (int i = 1; i <= PUBLISH_NUMBER; i++) {
                publisher.send(session.createTextMessage("我爱你哦,firstTopic!"));
            }
        } catch (Exception e) {
            LOGGER.error("向firstTopic发布消息异常", e);
        } finally {
            if (connection != null) {
                try {
                    connection.close();
                } catch (JMSException e) {
                    LOGGER.error("connection异常", e);
                }
            }
        }
    }
}

其实,Pub/Sub消息传递模型的编程思路与P2P消息传递模型的编程思路差不多,就是把queue换成topic而已。

订阅者:

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.log4j.Logger;

public class FirstSubscriber {
    private static Logger LOGGER = Logger.getLogger(FirstSubscriber.class);

    public static void main(String[] args) {
        ActiveMQConnectionFactory connectionFactory = null;
        TopicConnection connection = null;
        TopicSession session = null;
        Topic topic = null;
        TopicSubscriber subscriber = null;
        try {
            connectionFactory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_USER,
                    ActiveMQConnection.DEFAULT_PASSWORD, "tcp://192.168.220.128:61616");
            connection = connectionFactory.createTopicConnection();
            connection.start();
            session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
            topic = session.createTopic("firstTopic");
            subscriber = session.createSubscriber(topic);
            subscriber.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(Message message) {
                    try {
                        Thread.sleep(1000);
                        if (message instanceof TextMessage) {
                            TextMessage text = (TextMessage) message;
                            LOGGER.info(text.getJMSMessageID() + ": " + text.getText());
                        }
                    } catch (InterruptedException e) {
                        LOGGER.error("线程休眠异常", e);
                    } catch (JMSException e) {
                        LOGGER.error("firstSubscriber消費消息异常", e);
                    }
                }
            });
        } catch (Exception e) {
            LOGGER.error("firstSubscriber异常", e);
        }
    }
}

在本例中创建的订阅者不是持久化的,也就是说只能收到之后发布者发布的消息,接收不到之前发布者发布的消息。如果想要创建持久化的订阅者,需要用

session.createDurableSubscriber(Topic topic, String name),而且在此之前还必须要给session设置clientID,否则会报错。

session.setClientID(String clientID),这个有点疑惑,如果传一个常量字符串是可以的,如果传一个变量字符串,例如传System.currentTimeMillis()+""的话,就不起作用(只能接受到之后发布者发布的消息),这有点奇怪,不知是bug还是有其他什么原因!!!

优化版:

引入连接池。上面例子中与activemq服务端的连接都是调用createConnection()直接获得,用多少次连接就要创建多少次新的连接对象,所以可以引入连接池减少资源浪费。

需要导入commons-pool-xxx.jar包,pom.xml添加如下:

<!-- https://mvnrepository.com/artifact/commons-pool/commons-pool -->
<dependency>
    <groupId>commons-pool</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.4.2</version>
</dependency>

用org.apache.activemq.pool.PooledConnectionFactory包装ActiveMQConnectionFactory实例,随后可以设置PooledConnectionFactory实例的属性来实现连接池。如

setCreateConnectionOnStartup(boolean createConnectionOnStartup);//是否创建PooledConnectionFactory的时候就创建连接,默认是

setMaxConnections(int maxConnections);//设置最大连接数,默认值为8

setMaximumActiveSessionPerConnection(int maximumActiveSessionPerConnection) //设置每个连接可创建的session的最大数量,默认值为500

其实上面的setter方法都是继承自org.apache.activemq.pool.PooledConnectionFactory的父类org.apache.activemq.jms.pool.PooledConnectionFactory(org.apache.activemq.jms.pool.PooledConnectionFactory引用了commons-pool2-xxx.jar中的类,所以才需要导入commons-pool2-xxx.jar包)。

需要注意的是,5.12.0(不包括)以前版本的activemq-all-xxx.jar引用的是commons-pool-xxx.jar包中的类,这时候就需要导入commons-pool-xxx.jar包了。

更进一步,还可以引入线程池,使用多线程发送消息(用多线程操作send(Message message)方法)和消费消息(监听器的onMessage(Message message)方法中用多线程操作)。

具体代码示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;

import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.pool.PooledConnectionFactory;
import org.apache.log4j.Logger;

public class JMSProducer {
    Logger LOGGER = Logger.getLogger(JMSProducer.class);

    // 设置连接的最大连接数
    public final static int DEFAULT_MAX_CONNECTIONS = 2;
    private int maxConnections;

    // 线程池数量
    private int threadPoolSize;
    public final static int DEFAULT_THREAD_POOL_SIZE = 4;

    // 强制使用异步返回数据的格式
    private boolean useAsyncSend;
    public final static boolean DEFAULT_USE_ASYNC_SEND_FOR_JMS = true;

    // 连接地址
    private String brokerUrl;

    private String userName;

    private String password;

    private ExecutorService threadPool;

    private PooledConnectionFactory connectionFactory;

    public JMSProducer(String brokerUrl, String userName, String password) {
        this(brokerUrl, userName, password, DEFAULT_MAX_CONNECTIONS, DEFAULT_THREAD_POOL_SIZE,
                DEFAULT_USE_ASYNC_SEND_FOR_JMS);
    }

    public JMSProducer(String brokerUrl, String userName, String password, int maxConnections, int threadPoolSize,
            boolean useAsyncSendForJMS) {
        this.useAsyncSend = useAsyncSendForJMS;
        this.brokerUrl = brokerUrl;
        this.userName = userName;
        this.password = password;
        this.maxConnections = maxConnections;
        this.threadPoolSize = threadPoolSize;
        init();
    }

    private void init() {
        // 设置JAVA线程池
        this.threadPool = Executors.newFixedThreadPool(this.threadPoolSize);
        // ActiveMQ的连接工厂
        ActiveMQConnectionFactory actualConnectionFactory = new ActiveMQConnectionFactory(this.userName, this.password,
                this.brokerUrl);
        actualConnectionFactory.setUseAsyncSend(this.useAsyncSend);

        this.connectionFactory = new PooledConnectionFactory(actualConnectionFactory);// org.apache.activemq.pool.PooledConnectionFactory
        // 父类org.apache.activemq.jms.pool.PooledConnectionFactory的setter方法
        this.connectionFactory.setMaxConnections(this.maxConnections);
    }

    public void send(final String queue, final String text) {
        // 直接使用线程池来执行具体的调用
        this.threadPool.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    LOGGER.info(Thread.currentThread().getName());
                    sendMsg(queue, text);
                } catch (Exception e) {
                    LOGGER.error("发送失败", e);
                }
            }
        });
    }

    private void sendMsg(String queue, String text) throws Exception {
        Connection connection = null;
        Session session = null;
        try {
            // 从连接池工厂中获取一个连接
            connection = this.connectionFactory.createConnection();
            LOGGER.info("connection: " + connection);
            session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
            Destination destination = session.createQueue(queue);
            MessageProducer producer = session.createProducer(destination);
            Message message = getMessage(session, text);
            producer.send(message);
        } finally {
            closeSession(session);
            closeConnection(connection);
        }
    }

    private Message getMessage(Session session, String text) throws JMSException {
        return session.createTextMessage(text);
    }

    private void closeSession(Session session) {
        try {
            if (session != null) {
                session.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void closeConnection(Connection connection) {
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

写一个测试类测试上面的发送者:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

import org.apache.log4j.Logger;

public class JMSProducerTest {

    private static Logger LOGGER = Logger.getLogger(JMSProducerTest.class);

    public static void main(String[] args) {
        String brokerURL = "tcp://192.168.220.128:61616";
        JMSProducer producer = new JMSProducer(brokerURL, "admin", "admin");
        for (int i = 0; i < 6; i++) {
            LOGGER.info(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(LocalDateTime.now()));
            producer.send("firstQueue", UUID.randomUUID().toString().replaceAll("-", ""));
        }
    }
}

Activemq API使用(不整合spring)的更多相关文章

  1. Activemq API使用(整合spring)

    整合spring之后,主要用的就是org.springframework.jms.core.JmsTemplate的API了,在spring-jms-xxx.jar中. 引入整合需要的jar包: &l ...

  2. ActiveMQ 入门和与 Spring 整合

    ActiveMQ 入门演示 activemq 依赖 <dependency> <groupId>org.apache.activemq</groupId> < ...

  3. ActiveMQ第二弹:使用Spring JMS与ActiveMQ通讯

    本文章的完整代码可从我的github中下载:https://github.com/huangbowen521/SpringJMSSample.git 上一篇文章中介绍了如何安装和运行ActiveMQ. ...

  4. ActiveMQ(5.10.0) - Spring Support

    Maven Dependency: <dependencies> <dependency> <groupId>org.apache.activemq</gro ...

  5. activemq api的封装

    今天无聊写段代码..学习一下activemq,简单封装了一下activemq 的topic api.跟jdbc很类似 主要代码: import java.io.Serializable; import ...

  6. api网关揭秘--spring cloud gateway源码解析

    要想了解spring cloud gateway的源码,要熟悉spring webflux,我的上篇文章介绍了spring webflux. 1.gateway 和zuul对比 I am the au ...

  7. 框架源码系列十一:事务管理(Spring事务管理的特点、事务概念学习、Spring事务使用学习、Spring事务管理API学习、Spring事务源码学习)

    一.Spring事务管理的特点 Spring框架为事务管理提供一套统一的抽象,带来的好处有:1. 跨不同事务API的统一的编程模型,无论你使用的是jdbc.jta.jpa.hibernate.2. 支 ...

  8. 86. Spring Boot集成ActiveMQ【从零开始学Spring Boot】

    在Spring Boot中集成ActiveMQ相对还是比较简单的,都不需要安装什么服务,默认使用内存的activeMQ,当然配合ActiveMQ Server会更好.在这里我们简单介绍怎么使用,本节主 ...

  9. 消息中间件-activemq实战之整合Spring(四)

    前面的理论准备已经很充分,这一节我们来实战:将activemq整合到Spring框架才行中,因为Spring已经集成了JMS,这也为我们配置activermq带来了方便. 1. Spring对jms的 ...

随机推荐

  1. (转)Asp.Net底层原理(三、Asp.Net请求响应过程)

    原文地址:http://www.cnblogs.com/liuhf939/archive/2013/09/16/3324753.html 在之前,我们写了自己的Asp.Net框架,对整个流程有了一个大 ...

  2. mybatis使用count返回int的方法

    <select id="countByExample" resultType="java.lang.Integer" > select count( ...

  3. Dijstra算法-------为了纪念,等以后看的时候方便

    杭电problem2066 Time Limit : 1000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total ...

  4. PLSA的EM推导

    本文作为em算法在图模型中的一个应用,推导plsa的em算法. 1 em算法 em算法是解决一类带有隐变量模型的参数估计问题. 1.1 模型的定义 输入样本为,对应的隐变量为.待估计的模型参数为,目标 ...

  5. 移植 libevent-2.0.22-stable 到ARM平台

    ARM 移植: 移植简单来讲就是使用ARM的编译环境,重新编译一份ARM平台上可以使用的库或执行文件,一般只需要重新制定C编译器和C++编译器即可. 特别注意的地方: 不能从windows解压文件后再 ...

  6. 转载:java中抽象类和接口的作用与区别

    abstract class和interface是Java语言中对于抽象类定义进行支持的两种机制,正是由于这两种机制的存在,才赋予了Java强大的面向对象能力. abstract class和inte ...

  7. php+jquery 实现 ajax上传图片到非当前服务器

    用 html file控件上传图片,因为 $_FILES["file"] 是传到当前服务器,想要上传到另外一个服务器需要通过服务器脚本实现. 1.图片上传 引入jquery 和 a ...

  8. Hibernate学习第三天(2)(多对多关系映射)

    1.1.1      Hibernate多对多关系的配置 1.1.1.1   创建表 l   用户表 CREATE TABLE `sys_user` ( `user_id` bigint(32) NO ...

  9. 201621123012 《Java程序设计》第6周学习总结

    1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图或相关笔记,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰 ...

  10. ubuntu14.10,解决按照最新版Gnome 15.10后,经典Gnome桌面字体问题!

    ubuntu14.10刚安装完毕,我首先按照了经典Gnome桌面,随后我发现ubuntu软件中心里面能找到的软件明显不如先前我安装过的ubuntu了,我觉得有可能是因为我以前安装的ubuntu14.1 ...