1.JMS介绍
1. JMS:即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。
1)连接工厂。连接工厂(ConnectionFactory)是由管理员创建,并绑定到JNDI树中。客户端使用JNDI查找连接工厂,然后利用连接工厂创建一个JMS连接。
2)JMS连接。JMS连接(Connection)表示JMS客户端和服务器端之间的一个活动的连接,是由客户端通过调用连接工厂的方法建立的。
3)JMS会话。JMS会话(Session)表示JMS客户与JMS服务器之间的会话状态。JMS会话建立在JMS连接上,表示客户与服务器之间的一个会话线程。
4)JMS目的。JMS目的(Destination),又称为消息队列,是实际的消息源。
5)JMS生产者和消费者。生产者(Message Producer)和消费者(Message Consumer)对象由Session对象创建,用于发送和接收消息。
6)JMS消息通常有两种类型:
① 点对点(Point-to-Point)。在点对点的消息系统中,消息分发给一个单独的使用者。点对点消息往往与队列(javax.jms.Queue)相关联。
② 发布/订阅(Publish/Subscribe)。发布/订阅消息系统支持一个事件驱动模型,消息生产者和消费者都参与消息的传递。生产者发布事件,而使用者订阅感兴趣的事件,并使用事件。该类型消息一般与特定的主题(javax.jms.Topic)关联。
2 ActiveMQ介绍
要使用Java消息服务,你必须要有一个JMS提供者,管理会话和队列。既有开源的提供者也有专有的提供者。ActiveMQ就是JMS的开源的提供者。
1. Apache ActiveMQ(message queue):是Apache软件基金会所研发的开放源代码消息中间件;由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。
2.特色:
-
支持Java消息服务(JMS) 1.1 版本
-
集群 (Clustering)
-
支持的编程语言包括:C、C++、C#、Delphi、Erlang、Adobe Flash、Haskell、Java、JavaScript、Perl、PHP、Pike、Python和Ruby
3 何时使用消息队列?业务解耦、广播等
消息队列最本质的问题就是解耦,就是说一个事务,我们不需要关心,它需要什么系统,线程怎么调度的问题,只要有通知就可以了。举一个例子,我们的订单系统,支付成功后后来还有给用户发短信送积分等流程,如果短信网不好,那么这些流程的时间就会加长,用户这个购买订单的流程的总时间也会加长,可是我们不需要关心这些流程什么时候全部执行完,只需要有条通知,“您已支付成功就可以了’”。换句话说,对于我们的消息队列而言,我们只关注的是消息的“通知”,而不是“处理”的具体流程。
3 ActiveMQ的安装
step1:下载 apache-activemq-5.15.9-bin.zip 并解压http://activemq.apache.org/download-archives.html
step2:双击bin目录下的activemq.bat进行启动。
step3:访问http://localhost:8161,登录后出现这样的界面即为安装成功。
- Number Of Pending Messages 等待被处理的消息数量
- Number Of Consumers 消费者的数量
- Messages Enqueued 进入队列的消息
- Messages Dequeued 消息列中移除的消息
4 代码测试
4.1 点对点(Point-to-Point)queue
发送代码:
public class Producer {
private static final String userName=ActiveMQConnection.DEFAULT_USER;
private static final String password=ActiveMQConnection.DEFAULT_PASSWORD;
private static final String brokerURL=ActiveMQConnection.DEFAULT_BROKER_URL;
public static void main(String[] args) throws JMSException {
ConnectionFactory connectionFactory;
Connection connection;
Session session;
Destination destination;
MessageProducer producer;
TextMessage message;
//step1:创建一个连接工厂
connectionFactory=new ActiveMQConnectionFactory(userName,password,brokerURL);
//step2:从工厂里取得一个连接并打开
connection=connectionFactory.createConnection();
connection.start();
//step3:创建一个(session)会话对象 开启事务
session=connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//step4:使用会话对象创建目标对象(消息队列),包含queue和topic(一对一和一对多)
destination=session.createQueue("ActiveMQ_队列1");
//step5:使用会话对象创建生产者
producer=session.createProducer(destination);
//step6:使用会话对象创建一个消息对象
message=session.createTextMessage("发送了一条消息");
//step7:发送消息
producer.send(message);
//step8:提交事务
session.commit();
//step9:释放资源
connection.close();
}
}
接收代码:
public class Consumer {
private static final String userName=ActiveMQConnection.DEFAULT_USER;
private static final String password=ActiveMQConnection.DEFAULT_PASSWORD;
private static final String brokerURL=ActiveMQConnection.DEFAULT_BROKER_URL;
public static void main(String[] args) throws JMSException {
ConnectionFactory connectionFactory;
Connection connection;
Session session;
Destination destination;
MessageConsumer consumer;
//step1:创建一个连接工厂
connectionFactory=new ActiveMQConnectionFactory(userName, password, brokerURL);
//step2:从工厂里取得一个连接并打开
connection=connectionFactory.createConnection();
connection.start();
//step3:创建一个(session)会话对象 开启事务
session=connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//step4:使用会话对象创建目标对象(消息队列),包含queue和topic(一对一和一对多)
destination=session.createQueue("ActiveMQ_队列1");
//step5:使用会话对象创建生产者
consumer=session.createConsumer(destination);
//step6:注册消息监听,来监控生产者
consumer.setMessageListener(new MyMessageListener());
}
public class MyMessageListener implements MessageListener {
@Override
public void onMessage(Message message) {
try {
System.out.println("收到消息:"+((TextMessage)message).getText());
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试结果:
运行发送程序之后可以看到,队列里已经有一条消息了,但没有发送出去:
再运行接受程序,可以看到消息已经发出了:
4.2 发布/订阅(Publish/Subscribe)topic
紧接着对topic进行测试:
只需对上述queue的代码稍作修改,将createQueue()改为createTopic()即可
发送代码:
public class Producer {
private static final String userName=ActiveMQConnection.DEFAULT_USER;
private static final String password=ActiveMQConnection.DEFAULT_PASSWORD;
private static final String brokerURL=ActiveMQConnection.DEFAULT_BROKER_URL;
public static void main(String[] args) throws JMSException {
ConnectionFactory connectionFactory;
Connection connection;
Session session;
Destination destination;
MessageProducer producer;
TextMessage message;
//step1:创建一个连接工厂
connectionFactory=new ActiveMQConnectionFactory(userName,password,brokerURL);
//step2:从工厂里取得一个连接并打开
connection=connectionFactory.createConnection();
connection.start();
//step3:创建一个(session)会话对象 开启事务
session=connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);
//step4:使用会话对象创建目标对象(消息队列),包含queue和topic(一对一和一对多)
destination=session.createTopic("ActiveMQ_topic_2");
//step5:使用会话对象创建生产者
producer=session.createProducer(destination);
//step6:使用会话对象创建一个消息对象
message=session.createTextMessage("发送了一条topic消息");
//step7:发送消息
producer.send(message);
//step8:提交事务
session.commit();
//step9:释放资源
connection.close();
}
}
接收代码:
public class Consumer {
private static final String userName=ActiveMQConnection.DEFAULT_USER;
private static final String password=ActiveMQConnection.DEFAULT_PASSWORD;
private static final String brokerURL=ActiveMQConnection.DEFAULT_BROKER_URL;
public static void main(String[] args) throws JMSException {
ConnectionFactory connectionFactory;
Connection connection;
Session session;
Destination destination;
MessageConsumer consumer;
//step1:创建一个连接工厂
connectionFactory=new ActiveMQConnectionFactory(userName, password, brokerURL);
//step2:从工厂里取得一个连接并打开
connection=connectionFactory.createConnection();
connection.start();
//step3:创建一个(session)会话对象 开启事务
session=connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//step4:使用会话对象创建目标对象(消息队列),包含queue和topic(一对一和一对多)
destination=session.createTopic("ActiveMQ_topic_2");
//step5:使用会话对象创建生产者
consumer=session.createConsumer(destination);
//step6:注册消息监听,来监控生产者
consumer.setMessageListener(new MyMessageListener());
}
测试结果:
注意:正常情况下我们的topic消息不会再服务器持久化,所以要先打开消费者,再打开生产者,这个时候我们再运行生产者发送一条消息看到消息已经接收到。