Apache ActiveMQ™是最流行的开源,多协议,基于Java的消息服务器。它支持行业标准协议,因此用户可以通过广泛的语言和平台获得客户选择的好处。可以使用C,C ++,Python,.Net等连接。使用无处不在的AMQP协议集成您的多平台应用程序。
在官网下载最新的ActiveMQ http://activemq.apache.org/components/classic/download/
点击运行activemq.bat
或者
在cmd控制台运行 命令
cd [activemq_install_dir]
bin\ activemq start
比如我的安装路径是E:\software\apache-activemq-5.15.9\bin\win64
如果以管理员身份运行: InstallService.bat则会安装服务,如下图所示:
可以将服务设置为自动启动,当操作系统运行的时候自动启动服务,就无需运行activemq.bat或者执行 activemq start命令。
与windows安装并无太大差异。
从命令shell,切换到安装目录并ActiveMQ作为foregroud进程运行:
cd [activemq_install_dir]/bin
./activemq console
从命令shell,切换到安装目录并ActiveMQ作为daemon进程运行:
cd [activemq_install_dir]/bin
./activemq start
ActiveMQ实现了JMS,JMS中的一些关键接口如下:
ConnectionFactory:用于创建连接到消息中间件的连接工厂。
Connection:代表了应用程序和服务之间的连接通路。
Destination:指消息发布的地点,包括队列模式和主体模式。
Session:表示一个单线程的上下文,用于发送和接受消息。
MessageConsumer:由会话创建,用于接受发送到目的的消息。
MessageProducer:由会话创建,用于发送消息。
Message:是在消费者和生产者之间传递的对象,消息头,一组消息属性,和一个消息体。
org.apache.activemq
activemq-all
5.15.9
利用如下代码将消息发送到TEST.FOO队列
// Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("failover:(tcp://localhost:61616)?initialReconnectDelay=100");
// Create a Connection
Connection connection = connectionFactory.createConnection();
connection.start();
// Create a Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic or Queue)
Destination destination = session.createQueue("TEST.FOO");
// Create a MessageProducer from the Session to the Topic or Queue
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// Create a messages
String text = "Hello world! From: " + Thread.currentThread().getName() + " : " + this.hashCode();
TextMessage message = session.createTextMessage(text);
// Tell the producer to send the message
System.out.println("Sent message: "+ message.hashCode() + " : " + Thread.currentThread().getName());
producer.send(message);
// Clean up
session.close();
connection.close();
输出日志:
INFO | Successfully connected to tcp://localhost:61616
Sent message: 901950302 : Thread-0
在console的queues解密查看,TEST.FOO队列已经有一个消息
编写如下消费者代码
// Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
// Create a Connection
Connection connection = connectionFactory.createConnection();
connection.start();
connection.setExceptionListener(this);
// Create a Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic or Queue)
Destination destination = session.createQueue("TEST.FOO");
// Create a MessageConsumer from the Session to the Topic or Queue
MessageConsumer consumer = session.createConsumer(destination);
// Wait for a message
Message message = consumer.receive(1000);
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
String text = textMessage.getText();
System.out.println("Received: " + text);
} else {
System.out.println("Received: " + message);
}
consumer.close();
session.close();
connection.close();
输出日志:
Received: Hello world! From: Thread-0 : 1989096651
在console的queues解密查看,TEST.FOO队列已经有一个消息被消费,且队列当前消息数量为0,
与Queue模式类似只需将:
Destination destination = session.createQueue("TEST.FOO");
改为
Destination destination = session.createTopic("TEST.FOO");
运行,日志输出如下:
INFO | Successfully connected to tcp://localhost:61616
Sent message: 1597511522 : Thread-0
为了演示topic,需要启动多个线程,更改后的代码如下:
public class Consumer {
public static void main(String[] args) {
thread(new HelloWorldConsumer(), false);
thread(new HelloWorldConsumer(), false);
thread(new HelloWorldConsumer(), false);
}
public static void thread(Runnable runnable, boolean daemon) {
Thread brokerThread = new Thread(runnable);
brokerThread.setDaemon(daemon);
brokerThread.start();
}
public static class HelloWorldConsumer implements Runnable, ExceptionListener {
public void run() {
try {
// Create a ConnectionFactory
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");
// Create a Connection
Connection connection = connectionFactory.createConnection();
connection.start();
connection.setExceptionListener(this);
// Create a Session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// Create the destination (Topic or Queue)
Destination destination = session.createTopic("TEST.FOO");
// Create a MessageConsumer from the Session to the Topic or Queue
MessageConsumer consumer = session.createConsumer(destination);
// Wait for a message
Message message = consumer.receive(1000);
while (null == message) {
Thread.sleep(100);
message = consumer.receive(1000);
}
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
String text = textMessage.getText();
System.out.println("Received: " + text);
} else {
System.out.println("Received: " + message);
}
consumer.close();
session.close();
connection.close();
} catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
public synchronized void onException(JMSException ex) {
System.out.println("JMS Exception occured. Shutting down client.");
}
}
}
启动2个线程,运行后发现一直没有消费消息,但是在console界面发现队列里面是有消息没有被消费的,这是怎么回事呢?
原来:主题模式下,如果消费者是在生产者产生消息之后来的,那么是不会对之前的消息进行消费的
现在重新先运行consumer:
此时发现队列消费者数量为3,现在重新发送一条消息,在consumer客户端日志如下:
Received: Hello world! From: Thread-0 : 691909443
Received: Hello world! From: Thread-0 : 691909443
Received: Hello world! From: Thread-0 : 691909443
且消费的消息数量变为3条
同时我们发现,主题模式下,所有消费者都会消费同一个消息,也就是消息以广播的形式发送给每一个消费者
下章我们将使用spring boot进行消息的发送与消费
end