1.JMS简介

JMS的全称是Java Message Service,即Java消息服务。它主要用于在生产者和消费者之间进行消息传递,生产者负责产生消息,而消费者负责接收消息。把它应用到实际的业务需求中可以在特定的时候利用生产者生成消息,并进行发送,对应的消费者在接收到对应的消息后去完成对应的业务逻辑。对于消息的传递有两种类型,一种是点对点的,即一个生产者和一个消费者一一对应;另一种是发布/订阅模式,即一个生产者产生消息并进行发送后,可以由多个消费者进行接收。

JMS编程模型

(1) ConnectionFactory

创建Connection对象的工厂,针对两种不同的jms消息模型,分别有QueueConnectionFactory和TopicConnectionFactory两种。可以通过JNDI来查找ConnectionFactory对象。

(2) Destination

Destination的意思是消息生产者的消息发送目标或者说消息消费者的消息来源。对于消息生产者来说,它的Destination是某个队列(Queue)或某个主题(Topic);对于消息消费者来说,它的Destination也是某个队列或主题(即消息来源)。所以,Destination实际上就是两种类型的对象:Queue、Topic可以通过JNDI来查找Destination。

(3) Connection

Connection表示在客户端和JMS系统之间建立的链接(对TCP/IP socket的包装)。Connection可以产生一个或多个Session。跟ConnectionFactory一样,Connection也有两种类型:QueueConnection和TopicConnection。

(4) Session

Session是操作消息的接口。可以通过session创建生产者、消费者、消息等。Session提供了事务的功能。当需要使用session发送/接收多个消息时,可以将这些发送/接收动作放到一个事务中。同样,也分QueueSession和TopicSession。

(5) 消息的生产者

消息生产者由Session创建,并用于将消息发送到Destination。同样,消息生产者分两种类型:QueueSender和TopicPublisher。可以调用消息生产者的方法(send或publish方法)发送消息。

(6) 消息消费者

消息消费者由Session创建,用于接收被发送到Destination的消息。两种类型:QueueReceiver和TopicSubscriber。可分别通过session的createReceiver(Queue)或createSubscriber(Topic)来创建。当然,也可以session的creatDurableSubscriber方法来创建持久化的订阅者。

(7) MessageListener

消息监听器。如果注册了消息监听器,一旦消息到达,将自动调用监听器的onMessage方法。EJB中的MDB(Message-Driven Bean)就是一种MessageListener。

2.ActiveMQ简介

ActiveMQ是Apache软件基金下的一个开源软件,它遵循JMS规范(Java Message Service),是消息驱动中间件软件(MOM)。它为企业消息传递提供高可用,出色性能,可扩展,稳定和安全保障。ActiveMQ使用Apache许可协议。因此,任何人都可以使用和修改它而不必反馈任何改变。这对于商业上将ActiveMQ用在重要用途的人尤为关键。MOM的工作是在分布式的各应用之间调度事件和消息,使之到达指定的接收者。所以高可用,高性能,高可扩展性尤为关键。

  • ActiveMQ特性

⒈支持多种语言客户端,如:Java,C,C++,C#,Ruby,Perl,Python,PHP。应用协议有 OpenWire,Stomp REST,WS Notification,XMPP,AMQP。

⒉ 完全支持JMS1.1和J2EE1.4规范,它们包括同步和异步消息传递,一次和只有一次的消息传递,对于预订者的持久消息等。依附于JMS规范意味着,不论JMS消息提供者是谁,同样的基本特性(持久化,XA消息,事务)都是有效的。

⒊ 对Spring的支持,ActiveMQ可以很容易内嵌到使用Spring的系统里面去。

⒋ 通过了常见J2EE服务器(如 Geronimo,JBoss 4,GlassFish,WebLogic)的测试,其中通过JCA 1.5 resource adaptors的配置,可以让ActiveMQ可以自动的部署到任何兼容J2EE 1.4 商业服务器上。

⒌ ActiveMQ提供各种连接选择,包括HTTP,HTTPS,IP多点传送,SSL,STOMP,TCP,UDP,XMPP等。大量的连接协议支持使之具有更好的灵活性。很多现有的系统使用一种特定协议并且不能改变,所以一个支持多种协议的消息平台降低了使用的门槛。虽然连接很重要,但是和其他容器集成也同样重要。

6.ActiveMQ提供多种持久性方案可供选择,也可以完全按自己需求定制验证和授权。例如,ActiveMQ通过KahaDB提供自己的超快速消息持久方案(ultra-fast message persistence),但也支持标准的JDBC方案。ActiveMQ可以通过配置文件提供简单的验证和授权,也提供标准的JAAS登陆模块。

7.ActiveMQ是为开发者设计的。它并不需要专门的管理工具,因为它提供各种易用且强大的管理特性。有很多方法去监控ActiveMQ的各个方面,可以通过JMX使用JConsole或ActiveMQ web console;可以运行ActiveMQ消息报告;可以用命令行脚本;可以通过日志。

8.代理器集群(Broker clustering)----为了利于扩展,多个ActiveMQ broker能够联合工作。这个方式就是network of brokers并且能支持多种拓扑结构;支持客户端-服务器,点对点。

9.支持Ajax, 支持与Axis的整合

  • ActiveMQ优势

1.与OpenJMS、JbossMQ等开源jms provider相比,ActiveMQ有Apache的支持,持续发展的优势明显。

2.消息处理速度很快

3.提高系统资源的利用率,主要是任务的派发不是24小时平均的,而是高峰时期任务量很多,比如1秒1000多个,有的时候很低,比如十几秒钟才来一个。应用服务通过JMS队列一个一个的取任务,做完一个再领一个,使系统资源的运用趋于平均。比如ActiveMQ在赛扬(2.40GHz)机器上能够达到2000/s,消息大小为1-2k。好一些的服务器可以达到2万以上/秒。

3.ActiveMQ安装

ActiveMQ在linux服务上安装操作如下:

1.在官网下载activemq安装文件。地址:http://activemq.apache.org/download.html

2.上传下载的tar.gz安装文件到linux服务器上,并解压到指定目录:如 tar -xf apache-activemq-5.15.2-bin.tar.gz

3.运行activemq,进入到解压的 apache-activemq-5.15.2/bin目录,执行命令:activemq start

4.开放端口8161,61616,保证端口可访问。

运行activemq截图如下:

本机访问启动成功的activemq截图如下:

4.ActiveMQ类别及开发流程

   1)、Point-to-Point (点对点)消息模式开发流程
       1、生产者(producer)开发流程:

1.1 创建Connection: 根据url,user和password创建一个jms Connection。

1.2 创建Session: 在connection的基础上创建一个session,同时设置是否支持事务和ACKNOWLEDGE标识。

1.3 创建Destination对象: 需指定其对应的主题(subject)名称,producer和consumer将根据subject来发送/接收对应的消息。

1.4 创建MessageProducer: 根据Destination创建MessageProducer对象,同时设置其持久模式。

1.5 发送消息到队列(Queue): 封装Message消息,使用MessageProducer的send方法将消息发送出去。

2、消费者(consumer)开发流程:

2.1 实现MessageListener接口: 消费者类必须实现MessageListener接口,然后在onMessage()方法中监听消息的到达并处理。

2.2 创建Connection: 根据url,user和password创建一个jms Connection,如果是durable模式,还需要给connection设置一个clientId。

2.3 创建Session和Destination: 与ProducerTool.java中的流程类似,不再赘述。

2.4 创建replyProducer【可选】:可以用来将消息处理结果发送给producer。

2.5 创建MessageConsumer:  根据Destination创建MessageConsumer对象。

2.6 消费message:  在onMessage()方法中接收producer发送过来的消息进行处理,并可以通过replyProducer反馈信息给producer

   样例代码:

在消息生产者中定义一个队列,destination_request,提供消息,同时定义一个监听消息的队列拥有接受消费者回复的消息,destination_response。

 package com.tiantian.springintejms.test;

 import com.tiantian.springintejms.entity.Email;
import com.tiantian.springintejms.entity.TestMqBean;
import com.tiantian.springintejms.service.ProducerService;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.jms.*; @RunWith(SpringJUnit4ClassRunner.class)
public class ProducerSendTest { @Test
public static void main(String[] args) {
ConnectionFactory connectionFactory;
Connection connection;
Session session;
Destination destination_request,destination_response;
MessageProducer producer;
MessageConsumer consumer;
connectionFactory = new ActiveMQConnectionFactory("admin", "admin", "tcp://192.168.210.128:61616");
try {
connection = connectionFactory.createConnection();
connection.start();
//第一个参数是是否是事务型消息,设置为true,第二个参数无效
//第二个参数是
//Session.AUTO_ACKNOWLEDGE为自动确认,客户端发送和接收消息不需要做额外的工作。异常也会确认消息,应该是在执行之前确认的
//Session.CLIENT_ACKNOWLEDGE为客户端确认。客户端接收到消息后,必须调用javax.jms.Message的acknowledge方法。jms服务器才会删除消息。可以在失败的
//时候不确认消息,不确认的话不会移出队列,一直存在,下次启动继续接受。接收消息的连接不断开,其他的消费者也不会接受(正常情况下队列模式不存在其他消费者)
//DUPS_OK_ACKNOWLEDGE允许副本的确认模式。一旦接收方应用程序的方法调用从处理消息处返回,会话对象就会确认消息的接收;而且允许重复确认。在需要考虑资源使用时,这种模式非常有效。
//待测试
session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
destination_request = session.createQueue("request-queue");
destination_response = session.createQueue("response-queue");
producer = session.createProducer(destination_request);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); consumer = session.createConsumer(destination_response);
//优先级不能影响先进先出。。。那这个用处究竟是什么呢呢呢呢
TestMqBean bean = new TestMqBean();
bean.setAge(13);
for (int i = 0; i < 10; i++) {
bean.setName("send to data -" + i);
producer.send(session.createObjectMessage(bean));
}
producer.close();
System.out.println("消息发送成功..."); consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
if (null != message) {
TextMessage textMsg = (TextMessage) message;
System.out.println("收到回馈消息" +textMsg.getText());
}
} catch (Exception e) {
// TODO: handle exception
}
}
}); } catch (JMSException e) {
e.printStackTrace();
}
}
}

在消息消费者中定义一个队列,destination_request,用于接受消息,同时定义一个回复收到消息的队列回复生产者已经收到消息,destination_response。

 package com.tiantian.springintejms.test;

 import com.tiantian.springintejms.entity.TestMqBean;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.jms.*;
import java.util.Date; @RunWith(SpringJUnit4ClassRunner.class)
public class ConsumerReceiveTest { @Test
public static void main(String[] args) {
ConnectionFactory connectionFactory;
// Connection :JMS 客户端到JMS Provider 的连接
Connection connection = null;
// Session: 一个发送或接收消息的线程
final Session session;
// Destination :消息的目的地;消息发送给谁.
Destination destination_request,destination_response;
// 消费者,消息接收者
MessageConsumer consumer;
//回复接收到的消息
final MessageProducer producer;
connectionFactory = new ActiveMQConnectionFactory("admin", "admin", "tcp://192.168.210.128:61616");
try {
// 构造从工厂得到连接对象
connection = connectionFactory.createConnection();
// 启动
connection.start();
// 获取操作连接
//这个最好还是有事务
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
// 获取session注意参数值xingbo.xu-queue是一个服务器的queue,须在在ActiveMq的console配置
destination_request = session.createQueue("request-queue");
destination_response = session.createQueue("response-queue");
consumer = session.createConsumer(destination_request); producer= session.createProducer(destination_response);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT); consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
try {
TestMqBean bean = (TestMqBean) ((ObjectMessage) message).getObject();
System.out.println(bean);
if (null != message) {
System.out.println("收到消息" + bean.getName());
Message textMessage = session.createTextMessage("已经成功收到消息,现在开始回复"+new Date().toString());
producer.send(textMessage);
}
} catch (Exception e) {
// TODO: handle exception
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}

消息消费者收到消息,并打印出来,同时发送回复消息。截图如下:

消息生产者生产消息,同时接受到消费者回复的消息并打印出来。截图如下:

   2)、Publisher/Subscriber(发布/订阅者)消息模式开发流程 

1、订阅者(Subscriber)开发流程:

1.1 实现MessageListener接口: 在onMessage()方法中监听发布者发出的消息队列,并做相应处理。

1.2 创建Connection: 根据url,user和password创建一个jms Connection。

1.3 创建Session: 在connection的基础上创建一个session,同时设置是否支持事务和ACKNOWLEDGE标识。

1.4 创建Topic:  创建2个Topic, topictest.messages用于接收发布者发出的消息,topictest.control 用于向发布者发送消息,实现双方的交互。

1.5 创建consumer和producer对象:根据topictest.messages创建consumer,根据topictest.control创建 producer。

1.6 接收处理消息:在onMessage()方法中,对收到的消息进行处理,可直接简单在本地显示消息,或者根据消息内容不同处理对应的业务逻辑(比如:数据库更新、文件操作等等),并且可以使用producer对象将处理结果返回给发布者。

2、发布者(Publisher)开发流程:

2.1 实现MessageListener接口:在onMessage()方法中接收订阅者的反馈消息。

2.2 创建Connection: 根据url,user和password创建一个jms Connection。

2.3 创建Session: 在connection的基础上创建一个session,同时设置是否支持事务和ACKNOWLEDGE标识。

2.4 创建Topic: 创建2个Topic,topictest.messages用于向订阅者发布消息,topictest.control用于接 收订阅者反馈的消息。这2个topic与订阅者开发流程中的topic是一一对应的。

2.5 创建consumer和producer对象: 根据topictest.messages创建publisher; 根据topictest.control 创建consumer,同时监听订阅者反馈的消息。

2.6 给所有订阅者发送消息,并接收反馈消息。 注:可同时运行多个订阅者测试查看此模式效果 。

   样例代码:

消息发布者发布消息,定义一个主题example.A

 package com.tiantian.springintejms.test;

 import com.tiantian.springintejms.entity.TestMqBean;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.jms.*; @RunWith(SpringJUnit4ClassRunner.class)
public class TopicProducerSendTest { private static String user = "admin";
private static String password = "admin";
private static String url = "tcp://192.168.210.128:61616"; public static void main(String[] args)throws Exception {
// ConnectionFactory :连接工厂,JMS 用它创建连接
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);
// Connection :JMS 客户端到JMS Provider 的连接
Connection connection = connectionFactory.createConnection();
// Connection 启动
connection.start();
System.out.println("Connection is start...");
// Session: 一个发送或接收消息的线程
Session session = connection.createSession(Boolean.TRUE,Session.AUTO_ACKNOWLEDGE);
// Topicr :消息的目的地;消息发送给谁.
Topic destination = session.createTopic("example.A");
// MessageProducer:消息发送者
MessageProducer producer = session.createProducer(destination);
// 设置不持久化,此处学习,实际根据项目决定
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
// 构造消息,此处写死,项目就是参数,或者方法获取
sendMessage(session, producer);
session.commit(); connection.close();
System.out.println("send text ok.");
} public static void sendMessage(Session session, MessageProducer producer)
throws Exception {
for (int i = 1; i <= 10; i++) {//有限制
TextMessage message = session.createTextMessage("ActiveMq 发送的消息" + i);
// 发送消息到目的地方
System.out.println("发送消息:" + "ActiveMq 发送的消息" + i);
producer.send(message);
}
} }

消息订阅者接收消息,定义一个与发布者相对应的主题example.A。

 package com.tiantian.springintejms.test;

 import org.apache.activemq.ActiveMQConnectionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.jms.*; @RunWith(SpringJUnit4ClassRunner.class)
public class TopicSubscriberTest {
private static String user = "admin";
private static String password = "admin";
private static String url = "tcp://192.168.210.128:61616";
public static void main(String[] args) throws Exception{
// ConnectionFactory :连接工厂,JMS 用它创建连接
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user,password,url);
// Connection :JMS 客户端到JMS Provider 的连接
Connection connection = connectionFactory.createConnection();
connection.start();
// Session: 一个发送或接收消息的线程
final Session session = connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
// Destination :消息的目的地;消息发送给谁.
Topic destination=session.createTopic("example.A");
// 消费者,消息接收者
MessageConsumer consumer = session.createConsumer(destination);
consumer.setMessageListener(new MessageListener(){//有事务限制
@Override
public void onMessage(Message message) {
try {
TextMessage textMessage=(TextMessage)message;
System.out.println("接收到消息:"+textMessage.getText());
} catch (JMSException e1) {
e1.printStackTrace();
}
try {
session.commit();
} catch (JMSException e) {
e.printStackTrace();
}
}
});
}
}

消息发布者发布消息,并打印截图如下:

消息订阅者接受消息并打印截图如下:(消息订阅者需在发布者之前启动,可保证能取到订阅的消息)

3)、延迟消息发送

有时候不希望消息马上被broker投递出去,而是想要消息停留一段时间以后发给消费者,或者想让消息每隔一定时间投递一次,一共投递指定的次数。类似这种需求,ActiveMQ提供了一种broker端消息定时调度机制。开发者使用时只需要把几个描述消息定时调度方式的参数作为属性添加到消息,broker端的调度器就会按照定义的行为去处理消息。ActiveMQ定义调度消息参数为:

Property name type description
AMQ_SCHEDULED_DELAY long 延迟投递的时间
AMQ_SCHEDULED_PERIOD long 重复投递的时间间隔
AMQ_SCHEDULED_REPEAT int 重复投递次数
AMQ_SCHEDULED_CRON String Cron表达式
//延迟60秒发送消息
MessageProducer producer = session.createProducer(destination);
TextMessage message = session.createTextMessage("test msg");
long time = 60 * 1000;
message.setLongProperty(ScheduledMessage.AMQ_SCHEDULED_DELAY, time);
producer.send(message);
//基于CRON表达式定时投递消息
MessageProducer producer = session.createProducer(destination);
TextMessage message = session.createTextMessage("test msg");
message.setStringProperty(ScheduledMessage.AMQ_SCHEDULED_CRON, "0 * * * *");
producer.send(message);

5.源码下载

在Git上面下载:https://github.com/wuya11/SpringinteJMSonActiveMQ

ActiveMQ入门介绍的更多相关文章

  1. ActiveMQ介绍和ActiveMQ入门实例

    ActiveMQ百度百科   ActiveMQ入门实例-cnblogs.com      作者用的是5.5的版本,我测试时用的是5.6,按照作者说的整了一下,走得通

  2. 深入浅出 JMS(二) - ActiveMQ 入门指南

    深入浅出 JMS(二) - ActiveMQ 入门指南 上篇博文深入浅出 JMS(一) – JMS 基本概念,我们介绍了消息通信的规范JMS,这篇博文介绍一款开源的 JMS 具体实现-- Active ...

  3. ActiveMQ之一--ActiveMQ入门

    MQ的消费-生产者模型的一个典型的代表,一端往消息队列中不断的写入消息,而另一端则可以读取或者订阅队列中的消息.MQ和JMS类似,但不同的是JMS是SUN JAVA消息中间件服务的一个标准和API定义 ...

  4. ActiveMQ入门系列三:发布/订阅模式

    在上一篇<ActiveMQ入门系列二:入门代码实例(点对点模式)>中提到了ActiveMQ中的两种模式:点对点模式(PTP)和发布/订阅模式(Pub & Sub),详细介绍了点对点 ...

  5. ActiveMQ入门系列二:入门代码实例(点对点模式)

    在上一篇<ActiveMQ入门系列一:认识并安装ActiveMQ(Windows下)>中,大致介绍了ActiveMQ和一些概念,并下载.安装.启动他,还访问了他的控制台页面. 这篇,就用代 ...

  6. C# BackgroundWorker组件学习入门介绍

    C# BackgroundWorker组件学习入门介绍 一个程序中需要进行大量的运算,并且需要在运算过程中支持用户一定的交互,为了获得更好的用户体验,使用BackgroundWorker来完成这一功能 ...

  7. 初识Hadoop入门介绍

    初识hadoop入门介绍 Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不适用我们的项目,但是我会继续研究下去,技多不压身. < ...

  8. [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)

    最近在使用Python爬取网页内容时,总是遇到JS临时加载.动态获取网页信息的困难.例如爬取CSDN下载资源评论.搜狐图片中的“原图”等,此时尝试学习Phantomjs和CasperJS来解决这个问题 ...

  9. [Python爬虫] scrapy爬虫系列 <一>.安装及入门介绍

    前面介绍了很多Selenium基于自动测试的Python爬虫程序,主要利用它的xpath语句,通过分析网页DOM树结构进行爬取内容,同时可以结合Phantomjs模拟浏览器进行鼠标或键盘操作.但是,更 ...

随机推荐

  1. Shuttle ESB(一)——入门实例

    下载Shuttle ESB 从GitHub项目公布页,下载最新的公布版本号. Shuttle-ESB源代码包列表:http://www.nuget.org/packages?q=shuttle-esb ...

  2. 【CODEFORCES】 A. Dreamoon and Sums

    A. Dreamoon and Sums time limit per test 1.5 seconds memory limit per test 256 megabytes input stand ...

  3. Janus 二元神漏洞测试

    同步发表于:http://blog.hacktons.cn/2017/12/25/janus-demo/ 背景 12月9号,Andorid对外曝光了一个名为Janus的重量级系统漏洞CVE-2017- ...

  4. JAVA入门[18]-JdbcTemplate简单实例

    一.关于JdbcTemplate JdbcTemplate是最基本的Spring JDBC模板,这个模板支持简单的JDBC数据库访问功能以及基于索引参数的查询. Spring数据访问模板:在数据库操作 ...

  5. 【功能代码】---3 JS判断字符串是否包含某个字符串

    JS判断字符串是否包含某个字符串 var str ="abc"; if(str.indexOf("bc")>-1){ alert('str中包含bc字符串 ...

  6. 虚拟表dual。字符串函数UPPER,LOWER。&变量。INITCAP,LENGTH,SUBSTR

    &自定义变量的用法:

  7. JavaScript基础4——关于语句流程控制(分支语句、循环语句等)

    分支语句 (1)if...else...语句,基本格式分三种,如下 <script type="text/javascript"> var i=50; //if语句 i ...

  8. Node: 如何控制子进程的输出

    大家知道,在一个node程序中,如果当前进程想要生成一个子进程,它可以调用child_process模块的spawn方法.spawn方法签名如下: child_process.spawn(comman ...

  9. C语言位操作的算法

    1.头文件 #ifndef _INC_BITOPERATION #define _INC_BITOPERATION #endif /* 封装了所有的位操作运算 */ #include<stdio ...

  10. async和enterproxy控制并发数量

    聊聊并发与并行 并发我们经常提及之,不管是web server,app并发无处不在,操作系统中,指一个时间段中几个程序处于已经启动运行到完毕之间,且这几个程序都是在同一处理机上运行,并且任一个时间点只 ...