【JavaEE】经典JAVA EE企业应用实战-读书笔记4

本文详细介绍了Java消息服务(JMS)的基本概念与操作流程,包括消息的同步与异步接收方式,以及PTP与Pub-Sub两种消息模型的区别。探讨了如何通过JNDI查找连接工厂、创建连接和会话等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

消息是不同应用程序之间,或同一个应用程序的不同组件之间的通信方法,当一个应用程序或一个组件将消息发送到指定的消息目的之后,该消息可以被一个或多个组件读取并处理。

消息生产者将消息发送到消息服务器,消息服务器使用消息队列来保存消息,而消息消费者则通过消息队列来依次读取每条消息,这就是典型的PTPPeer To Peer,点对点)模型。

Pub-SubPublish/Subscribe,发布/订阅)模型而言,消息生产者将消息发送消息服务器的指定主题,而消息服务器则将该消息转发到订阅该主题的每个消息消费者。

JMS系统中大致包含如下基本对象

1)连接工厂:有服务器管理员创建,并绑定到JNDI树上,JMS客户端使用JNDI查找、定位连接工厂,然后利用连接工厂创建JMS连接。

2)JMS连接:表示客户机与服务器之间的活动连接。通过连接工厂创建连接。通常,每个客户机使用单独的连接,而每个连接则可以连接多个JMS目的。

3)JMS会话:表示客户机与JMS服务器之间的通信状态。JMS会话建立在连接之上,表示JMS客户机与服务器之间的通信线程。会话定义了消息的顺序。JMS使用会话进行事务性的消息处理。

4)JMS消息目的:即消息生产者发送消息的目的地,也是消息消费者获取消息的消息源。

5)消息生产者:负责创建消息并将消息发送到消息目的。

6)消息消费者:负责接收消息并读取消息内容。

JMS主要有两个版本1.0.21.1JMS1.0.2API为每个消息模型提供了两种不同的类体系,JMS1.1则使用统一的域模型,从而减少两种模型之间的差别,避免客户端代码的差别。

 


 

不管是使用PTP还是Pub-Sub,发送的步骤可以归纳如下

1)通过JNDI查找来获取JMS连接工厂

2)JMS连接工厂创建JMS连接

3)JMS连接创建JMS消息会话

4)JMS消息会话创建消息生产者

5)JMS消息会话创建空的JMS消息

6)JMS消息调用自身的方法填充内容

7)通过JNDI查找获取JMS消息目的

8)消息生产者将消息发送到指定的JMS消息目的

9)关闭JMS资源

public void sendMessage() throws NamingException, JMSException {

  final String CONNECTION_FACTORY_JNDI = "ConnectionFactory";

  Context ctx = getInitialContext();

  ConnectionFactory connFactory = (ConnectionFactory) ctx.lookup(CONNECTION_FACTORY_JNDI);

  Destination dest = (Destination) ctx.lookup("MessageQueue");

  Connection conn = connFactory.createConnection();

  Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

  MessageProducer sender = session.createProducer(dest);

  sender.setDeliveryMode(DeliveryMode.PERSISTENT);

  sender.setTimeToLive(20000);

  TextMessage msg = session.createTextMessage();

  msg.setText("Hello");

  sender.send(msg);

  msg.setText("Welcome to JMS");

  sender.send(msg);

  session.close();

  conn.close();

}

private Context getInitialContext() {

  final String INIT_FACTORY = "org.jnp.interfaces.NamingContextFactory";

  final String SERVER_URL = "jnp://localhost:1099";

  Context ctx = null;

  try {

    Properties prop = new Properties();

    prop.put(Context.INITIAL_CONTEXT_FACTORY, INIT_FACTORY);

    prop.put(Context.PROVIDER_URL, SERVER_URL);

    ctx = new InitialContext(prop);

  } catch (NamingException e) {

    e.printStackTrace();

  }

  return ctx;

}

public static void main(String[] args) throws Exception {

  MessageSender mp = new MessageSender();

  mp.sendMessage();

}

上面的代码中创建Session时调用了Connection的如下方法

Session createSession(boolean transacted,int acknowledgeMode):该方法的前一个参数表明创建的会话是否具有事务性,后一个参数是消息的确认方式。

消息的确认是指当消息接受者收到消息,并做出了对应处理之后,他将回送一个确认消息。对于非事务性会话,创建会话时应该指定确认方式。JMS定义了3中确认方式

AUTO_ACKNOWLEDGE:对于同步消费者,Receive方法调用返回且没有异常发生时,将自动对收到的消息予以确认。对于异步消息,当onMessage方法放回且没有异常发生时,即收到的消息自动确认。

CLIENT_ACKNOWLEDGE:要求客户端使用javax.jms.Message.acknowledge()方法完成确认。

DUPS_OK_ACKNOWLEDGE:允许JMS不必急于确认收到的消息,允许在收到多个消息之后一次完成确认。与AUTO_ACKNOWLEDGE相比,这种确认方式在某些情况下可能更有效,因为没有确认,当系统崩溃或网络出现故障时,消息可以被重新传递。

 

PTP消息的同步接收,步骤如下

1)通过JNDI查找来获取JMS连接工厂

2)通过JMS连接工厂创建JMS连接工厂

3)JMS连接创建JMS会话

4)通过JNDI查找获取JMS消息目的

5)JMS会话根据指定的JMS消息目的来创建一个JMS消息消费者

6)JMS消费者接收消息

7)关闭JMS资源

在同步接收策略中,JMS消费者调用receive()方法从消息目的视图获取消息,有两个重载版本

Message receive():读取下一条JMS消息,该方法将会一直阻塞线程

Message receive(long timeout):读取下一条JMS消息,如果没有读到消息,该方法将会阻塞timeout毫秒,如果经过timeout毫秒依然没有读到,将会返回null

Message receiveNoWait():该方法不会阻塞线程,他尝试从消息队列读取消息,如果消息队列中有可用的消息,该方法返回读到的消息,否则返回null

public void receiveMessage() throws JMSException, NamingException {

  final String CONNECTION_FACTORY_JNDI = "";

  Context ctx = getInitialContext();

  ConnectionFactory connFactory = (ConnectionFactory) ctx.lookup(CONNECTION_FACTORY_JNDI);

  Destination dest = (Destination) ctx.lookup("MessageQueue");

  Connection conn = connFactory.createConnection();

  conn.start();

  Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

  MessageConsumer receiver = session.createConsumer(dest);

  TextMessage msg = (TextMessage) receiver.receive();

  System.out.println(msg);

  session.close();

  conn.close();

}

PTP消息的异步接收

类似于AWT的事件编程,JMS消息消费者并不主动调用receive()方法去接收消息,而是采用一种监听器的机制来监听消息目的,当有消息抵达消息目的时,JMS消费者将自动触发他锁对应的监听器的监听方法。

JMS为消息的异步接收提供了MessageListener接口,这是一个标准的事件监听接口,实现该接口的类必须实现如下方法

public void onMessage(Message m):当JMS消息目的有消息送达时,JMS消息监听器的该监听方法将被触发。

public AsyncConsumer() throws JMSException, NamingException, InterruptedException {

  final String CONNECTION_FACTORY_JNDI = "";

  Context ctx = getInitialContext();

  ConnectionFactory connFactory = (ConnectionFactory) ctx.lookup(CONNECTION_FACTORY_JNDI);

  Destination dest = (Destination) ctx.lookup("MessageQueue");

  Connection conn = connFactory.createConnection();

  conn.start();

  Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);

  MessageConsumer receiver = session.createConsumer(dest);

  receiver.setMessageListener(this);

  Thread.sleep(20000);

  session.close();

  conn.close();

}

@Override

public void onMessage(Message m) {

  TextMessage msg = (TextMessage) m;

  System.out.println(msg);

  try {

    System.out.println(msg.getText());

  } catch (JMSException e) {

    e.printStackTrace();

  }

}

public static void main(String[] args) throws Exception {

  AsyncConsumer consumer = new AsyncConsumer();

}

对于Pub-Sub消息模型而言,当多个消息消费者同时订阅某个主题时,只要有一个消息生产者向该主题发布一条消息,每个消息消费者都可以收到一个消息的副本;而对于PTP消息模型来说,当消息生产者向消息队列发送一条消息之后,只有一个消息消费者可以接收到该消息。

对于Pub-Sub消息模型而言,当消息生产者将某个消息发布到指定主题时,即使某个消息消费者订阅了该主题,但如果该消息抵达消息主题时该消息消费者处于离线状态,他将无法收到该消息;而对于PTP消息模型来说,当消息生产者向消息队列发送一条消息时,即使消息消费者处于离线状态,只要该消息还处于有效期内,该消息消费者总可以从消息队列中提取到该消息。

 

可靠的JMS订阅

使用这种可靠的订阅模式,客户端必须提供一个唯一的标识符,可以保证离线的消费者也能接收到消息。

Connection conn=connFactory.createConnection();

//设置客户端ID

conn.setClientID(kingdz);

//创建可靠的消息订阅者

TopicSubscriber receiver=session.createDurableSubscriber(dest,kingdz);

当一个可靠的消息订阅者处于离线状态时,JMS服务器必须保存需要送达该主题的所有消息,才能保证可靠的消息订阅者不会错过任何消息。这将强制JMS服务器必须保存这些消息的副本,知道所有的可靠的消息订阅者都收到这些消息为止。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值