ActiveMQ——1.初识ActiveMQ
来源:互联网 发布:软件侵权的证据 编辑:程序博客网 时间:2024/06/01 10:02
前言
中间件
由于业务的不同、技术的发展、硬件和软件的选择有所差别,导致了异构组件或应用并存的局面。要使这些异构的组件协同工作,一个有效的方式就是提供一个允许它们进行通信的层,该层即为中间件。
在概念上,中间件位于应用程序层与平台层(操作系统和底层网络服务)之间:
分类:
- 基于远程过程调用(Remote Procedure Call, RPC)的中间件
允许一个应用程序中的过程调用远程应用程序中的过程,就好像它们是本地调用一样。 - 基于对象请求代理(Object Request Broker, ORB)的中间件
- 面向消息(Message-Oriented Middleware,MOM)的中间件
使分布式应用程序可以通过发送和接收消息来进行通信和交换数据。
MOM
全称:Message-Oriented Middleware 中文:面向消息的中间件。
MOM通信模型:
MOM模型中的四个基本元素:消息传递提供者、目的地、客户端(发送方或接收方)、消息。
发送方客户端将消息发送到消息提供者维护的目的地,这些消息一直被保留直到接收方客户端将消息取出。
JMS
全称:Java Message Service 中文:Java消息服务。
JMS是Java的一套API标准,最初的目的是为了使应用程序能够访问现有的MOM系统(客户端通过JMS访问消息提供者);后来被许多现有的MOM供应商采用,并实现为MOM系统。
基于JMS实现的MOM,又被称为JMS Provider。
ActiveMQ
Apache出品,完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现。
它有很多功能、特色,所以它的详细信息很复杂。但是基于这一刻,我们只需要知道两件事:(1) 它是MOM;(2) 它是JMS的一个实现。
相互关系
参考:点击打开链接
正文
JMS客户端编程模型
消息传送模式
消息传送模式又称为消息传送域,JMS API定义了两种模式:PTP和Pub/Sub。PTP
- 一个Message只能交给一个Receiver;这里的Message像是一个消耗品。
- 只要Queue中有Message,Receiver就能获取到。
Pub/Sub
- 一个Message可以复制多份,交给多个Subscriber。
- 先订阅,再获取 - Subscriber只能获取订阅之后发送到Topic的Message。
角色定位
JMS API
统一域和特定于域的API
编程模型
对象简介
- 连接工厂(ConnectionFactory)
客户端使用连接工厂对象(ConnectionFactory)创建连接。 - 连接(Connection)
连接对象 (Connection) 表示客户端与代理之间的活动连接。创建连接时会分配通信资源并对客户端进行验证。这是一个相当重要的对象,大多数客户端均使用一个连接来完成所有的消息传送。连接支持并发使用:一个连接可由任意数量的生成方和使用方共享。 - 会话(Session)
如果连接代表客户端与代理之间的通信渠道,则会话标记客户端与代理之间的单次对话。会话对象主要用于创建消息、消息生成方和消息使用方。 - 消息(Message)
消息封装一次通信的内容。消息由三部分组成:消息头、属性和主体。 - 消息生成方(MessageProducer)
由Session创建,负责发送Message到目的地。 - 消息使用方(MessageConsumer)
由Session创建,负责从目的地中消费Message。 - 目的地(Destination)
JMS Provider负责维护,用于对Message进行管理的对象。MessageProducer需要指定Destination才能发送消息,MessageReceiver需要指定Destination才能接收消息。
demo
Error occurred during initialization of VM
Could not reserve enough space for object heap
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.
if "%ACTIVEMQ_OPTS%" == "" set ACTIVEMQ_OPTS=-Xms1G -Xmx1G将Xms和Xmx适当调小,如256M。
1.producer-client
文件目录结构
pom.xmlsrc/main/resources/ |---- jndi.propertiessrc/main/java/ |---- cn.sinobest.asj.producer.jms.clientmode |---- SimpleProducer.java # 基于客户端编程模型,发送消息给ActiveMQ
文件内容
1.pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.sinobest.asj</groupId> <artifactId>jms-producer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>jms-producer</name> <description>基于ActiveMQ的Producer Client。</description> <dependencies> <!-- import activemq-client to send message to ActiveMQ --> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-client</artifactId> <version>5.13.2</version> </dependency> <!-- not necessary, import to remove the warn message from activemq-client --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.19</version> </dependency> </dependencies></project>
2.jndi.properties
java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory# use the following property to configure the default connectorjava.naming.provider.url=tcp://localhost:61616# register some queues in JNDI using the form# queue.[jndiName] = [physicalName]queue.exampleQueue=example.queue# register some topics in JNDI using the form# topic.[jndiName] = [physicalName]topic.exampleTopic = example.topic
说明:
- java.naming.factory.initial
定义ConnectionFactory的实例化类。 - java.naming.provider.url
定义broker的url,这个是ActiveMQ默认的url。 - queue.exampleQueue
定义了一个Queue Destination。name为example.queue,JNDI的name为exampleQueue。 - topic.exampleTopic
定义了一个Topic Destination。name为example.topic,JNDI的name为exampleTopic。
3.SimpleProcedure.java
package cn.sinobest.asj.producer.jms.clientmode;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 javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;/** * A simple demo for producer client to send message to ActiveMQ.<br> * refer to <a href="http://activemq.apache.org/jndi-support.html">JNDI * Support</a> * * @author lijinlong */public class SimpleProducer { /** JNDI name for ConnectionFactory */ static final String CONNECTION_FACTORY_JNDI_NAME = "ConnectionFactory"; /** JNDI name for Queue Destination (use for PTP Mode) */ static final String QUEUE_JNDI_NAME = "exampleQueue"; /** JNDI name for Topic Destination (use for Pub/Sub Mode) */ static final String TOPIC_JNDI_NAME = "exampleTopic"; /** * @param args */ public static void main(String[] args) { Context jndiContext = null; ConnectionFactory connectionFactory = null; Connection connection = null; Session session = null; Destination destination = null; MessageProducer producer = null; // create a JNDI API IntialContext object try { jndiContext = new InitialContext(); } catch (NamingException e) { System.out.println("Could not create JNDI Context:" + e.getMessage()); System.exit(1); } // look up ConnectionFactory and Destination try { connectionFactory = (ConnectionFactory) jndiContext .lookup(CONNECTION_FACTORY_JNDI_NAME); // look up QUEUE_JNDI_NAME for PTP Mode // look up TOPIC_JNDI_NAME for Pub/Sub Mode destination = (Destination) jndiContext.lookup(QUEUE_JNDI_NAME); } catch (NamingException e) { System.out.println("JNDI look up failed:" + e.getMessage()); System.exit(1); } // send Messages and finally release the resources. try { connection = connectionFactory.createConnection(); session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); producer = session.createProducer(destination); TextMessage message = session.createTextMessage(); for (int i = 0; i < 3; i++) { message.setText(String.format("This is the %dth message.", i + 1)); producer.send(message); } } catch (JMSException e) { e.printStackTrace(); } finally { try { if (session != null) session.close(); if (connection != null) connection.close(); } catch (JMSException e) { e.printStackTrace(); } } }}SimpleProcedure.java
- 第23行声明的JNDI name for ConnectionFactory的值是固定的。
- 第25行声明的JNDI name for Queue的值,对应于jndi.properties的queue的jndi name。
- 第27行声明的JNDI name for Topic的值,对应于jndi.properties的topic的jndi name。
- 第55行look up Destination的实例,参数取QUEUE_JNDI_NAME或TOPIC_JNDI_NAME,分别对应PTP模式和Pub/Sub模式。
2.consumer-client
pom.xmlsrc/main/resources/ |---- jndi.propertiessrc/main/java/ |---- cn.sinobest.asj.consumer.jms.clientmode |---- SimpleConsumer.java # 基于客户端编程模型,从ActiveMQ接收消息
文件内容
1.pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.sinoebst.asj</groupId> <artifactId>jms-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>jms-consumer</name> <description>基于ActiveMQ的Consumer Client。</description> <dependencies> <!-- import activemq-client to receive message from ActiveMQ --> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-client</artifactId> <version>5.13.2</version> </dependency> <!-- not necessary, import to remove the warn message from activemq-client --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.19</version> </dependency> </dependencies></project>
2.jndi.properties
java.naming.factory.initial=org.apache.activemq.jndi.ActiveMQInitialContextFactory# use the following property to configure the default connectorjava.naming.provider.url=tcp://localhost:61616# register some queues in JNDI using the form# queue.[jndiName] = [physicalName]queue.exampleQueue=example.queue# register some topics in JNDI using the form# topic.[jndiName] = [physicalName]topic.exampleTopic = example.topic
3.SimpleConsumer.java
package cn.sinobest.asj.consumer.jms.clientmode;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.JMSException;import javax.jms.Message;import javax.jms.MessageConsumer;import javax.jms.Session;import javax.jms.TextMessage;import javax.naming.Context;import javax.naming.InitialContext;import javax.naming.NamingException;/** * A simple demo for consumer to receive message from ActiveMQ.<br> * * @author lijinlong * */public class SimpleConsumer { /** JNDI name for ConnectionFactory */ static final String CONNECTION_FACTORY_JNDI_NAME = "ConnectionFactory"; /** JNDI name for Queue Destination (use for PTP Mode) */ static final String QUEUE_JNDI_NAME = "exampleQueue"; /** JNDI name for Topic Destination (use for Pub/Sub Mode) */ static final String TOPIC_JNDI_NAME = "exampleTopic"; /** * @param args */ public static void main(String[] args) { Context jndiContext = null; ConnectionFactory connectionFactory = null; Connection connection = null; Session session = null; Destination destination = null; MessageConsumer consumer = null; // create a JNDI API IntialContext object try { jndiContext = new InitialContext(); } catch (NamingException e) { System.out.println("Could not create JNDI Context:" + e.getMessage()); System.exit(1); } // look up ConnectionFactory and Destination try { connectionFactory = (ConnectionFactory) jndiContext .lookup(CONNECTION_FACTORY_JNDI_NAME); // look up QUEUE_JNDI_NAME for PTP Mode // look up TOPIC_JNDI_NAME for Pub/Sub Mode destination = (Destination) jndiContext.lookup(QUEUE_JNDI_NAME); } catch (NamingException e) { System.out.println("JNDI look up failed:" + e.getMessage()); System.exit(1); } // receive Messages and finally release the resources. try { connection = connectionFactory.createConnection(); connection.start(); // connection should be called in // receiver-client session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); consumer = session.createConsumer(destination); long timeout = 10 * 1000; for (Message message = consumer.receive(timeout); message != null; message = consumer .receive(timeout)) { String text = ((TextMessage) message).getText(); System.out.println(String.format("receive a message:%s", text)); } } catch (JMSException e) { e.printStackTrace(); } finally { try { if (session != null) session.close(); if (connection != null) connection.close(); } catch (JMSException e) { e.printStackTrace(); } } }}SimpleConsumer.java
说明:在第65行调用了Connection#start方法,否则无法收到消息(目前不明白原因)。
3.测试
3.1.基于PTP Mode测试
- 确保SimpleProducer和SimpleConsumer中,都是根据QUEUE_JNDI_NAME来look up Destination实例的。
- 确保ActiveMQ启动正常。
- 运行SimpleProducer。
- 运行SimpleConsumer - 看到信息输出。
3.2.基于Pub/Sub测试
- 确保SimpleProducer和SimpleConsumer中,都是根据TOPIC_JNDI_NAME来look up Destination实例的。
- 确保ActiveMQ启动正常。
- 运行SimpleConsumer。
Pub/Sub的其中一个特点是:先订阅,再接收。所以要先运行Consumer。 - 尽快运行SimpleProducer。
Consumer设置的timeout是10s,如果10s内没有收到消息就会退出。 - SimpleConsumer的控制台有输出信息。
输出内容和PTP的测试结果一致。
4.编程获取ConnectionnFactory和Destination
// 创建工厂实例// javax.jms.ConnectionFactory// org.apache.activemq.ActiveMQConnectionFactoryConnectionFactory connectionFactory = new ActiveMQConnectionFactory( ActiveMQConnectionFactory.DEFAULT_USER, ActiveMQConnectionFactory.DEFAULT_PASSWORD, ActiveMQConnectionFactory.DEFAULT_BROKER_URL);// javax.jms.ConnectionConnection connection = connectionFactory.createConnection();// javax.jms.SessionSession session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);// 创建目的地// javax.jms.DestinationDestination destination = session.createQueue("example.queue");Destination destination = session.createTopic("example.topic");
参考文档:https://docs.oracle.com/cd/E19148-01/820-0533/aerbg/index.html
- ActiveMQ——1.初识ActiveMQ
- 初识ActiveMQ
- 初识ActiveMQ
- 初识activeMQ
- 初识activemq
- ActiveMQ系列—ActiveMQ安装
- ActiveMQ——如何监控ActiveMQ
- ActiveMQ——2、ActiveMQ API详解
- 初识ActiveMQ消息中间件
- ActiveMQ初识及安装
- 初识ActiveMQ消息中间件
- activeMQ——集群
- 一点点积累—activemq
- ActiveMQ—消息队列
- ActiveMQ
- ACtiveMQ
- ACtiveMQ
- activeMQ
- 设计模式之单例模式
- ES6学习(一)——let和const命令
- Jedis使用中的几个概念
- typedef
- oracle服务都启动了,但是database control orcl https://localhost:1158/em还是打不开怎么办
- ActiveMQ——1.初识ActiveMQ
- 简易三维重建(二) SIFT提取特征向量
- 特征分解和奇异值分解(SVD)
- 机房收费系统——详细设计说明书
- 简单MVP框架(OKHTTP请求数据)
- 【MySQL】---1045-Access denied for user 'root'@'localhost'(using password :YES)
- Deep Learning论文笔记之(四)CNN卷积神经网络推导和实现
- struct 结构体
- org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter问题解决