EJB3学习笔记_Message-Driven Bean

Why Messageing

 

1、Asynchrony(异步)

  • A typical RMI-IIOP(Session Bean) client must wait while the server performs its processing

2、Decoupling(解耦)

  • An RMI-IIOP client has to know the individual servers it wants to use

3、Reliability(可靠)

  • When an RMI--IIOP client calls the server, the latter has to be running

4、Support for multiple senders and receivers(多点发送,多点接受)

  • RMI-IIOP limits you to a single client talking to a single server at any given time

 

面向消息编程也可以说时一种SOA的实现。

 

中间通过消息中间件,缓存和分发消息。

 

 

 

 

Message Oriented Middleware(MOM)

 

 

1、MOM is a term used to refer to any infrastructure that supports messaging

2、MOM products

  • IBM WebSphere MQ
  • BEA tuxedo/Q
  • Microsoft MSMQ
  • Sun Java System Messaging Server
  • Tibco Rendezvous
  • Sonic Software SonicMQ
  • FioranoMQ

 

 

The Java Message Service(JMS)

 

目标:使用统一的API 去访问不同的消息服务中间件

1、Is a messaging standard designed to eliminate many of the disadvantages that MOM-based products faced

2、Has two parts

  • An API

          we use it to write code to send and receive messages

  • A Service Provider Interface(SPI)

         Plug in JMS providers

         A JMS provider knows how to talk to a specific MOM implementation

 

 

 

Messaging Domains

 

消息的两种方式

1、发布/订阅 的方式 , 基于主题的

  • 允许多个接受者,类似于广播的方式
  • 生产者将消息发送到主题上(Topic)
  • 接受者必须先订阅

2、点对点 的方式 , 基于队列的

  • 一个消息只能被一个接受者接受一次
  • 生产者把消息发送到队列中(Queue),这个队列可以理解为电视机频道(channel)
  • 在这个消息中间件上有多个这样的channel
  • 接受者无需订阅,当接受者未接受到消息时就会处于阻塞状态

 

 

 

 

 

Client View of a JMS System

 

  1. 获得JMS驱动(封装了与特定消息服务器交互的协议)(类似JDBC驱动),j2ee服务器会把驱动绑定到JNDI上,可以以此获得
  2. 通过工厂创建连接 Connection  ,代表到特定目标的一个链路(也和JDBC是一码事)。
  3. 创建会话 Session , 每个会话都代表一个事务。(就比如多线程,大家共用一个Connection,但Session都是自己的)
  4. 从JNDI中查询 生产者消息发送的目的地,消费者消费的来源,这些目标信息。(所以需要在应用服务器中配置好这些目标)
  5. 创建基于当前会话的 生产者和消费者。(JMS Producer Or JMS Consumer),创建时需要参数
  6. 发送和接受消息(send or receive message)

 

 

 

 

 

使用Jboss部署 Topic/Queue

 

 

1、打开Jboss控制台(http://localhost:8080/jmx-console/)

2、找到域 jboss.mq  , 找到服务 service=DestinationManager(目标管理器)

3、这个bean提供了创建队列和主题的方法(createQueue()和createTopic()),都需要2个参数,一个名字,一个JNDI名字

 

 例子:创建队列

 

可以再控制台查看到此队列:(这些都是临时的,重启服务后就没了,不过可以通过配置文件预先创建)

 

 

通过客户端去连接

 

点对点的

 

创建生产者:

import javax.jms.*; import javax.naming.*; public class Producer{ public static void main(String[] args)throws NamingException{ Context ctx = new InitialContext(); ConnectionFactory cf = (ConnectonFactory)ctx.lookup("ConnectionFactory");//名字在Jboss中缺省就叫ConnectionFactory Destination des = (Destination)ctx.lookup("queue/Testqueue");//查询目标 Connection con = cf。createConnection();//创建连接 Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE);/*创建会话,第一个参数标示是否使用事务,第二个表示自动通知,指收到消息后自动恢复消息中间件,中间件就会认为你收到了然后把消息删除,如果不是自动通知则意味可以重复接受消息,在这里是生产者,这个参数没有意思,但API如此,只能写。*/ MessageProducer producer = session.createProducer(des);//创建消息生产者,传入基于的目标 TextMessage msg = session.createTextMessage();//创建message,这里TextMessage是一个子类。 msg.setText("clat"); producer.send(mgs); con.close(); System.out.println("over!"); } }

 

 

创建消费者:

 

import javax.jms.*; import javax.naming.*; public class Producer{ public static void main(String[] args)throws NamingException{ Context ctx = new InitialContext(); ConnectionFactory cf = (ConnectonFactory)ctx.lookup("ConnectionFactory");//名字在Jboss中缺省就叫ConnectionFactory Destination des = (Destination)ctx.lookup("queue/Testqueue");//查询目标 Connection con = cf。createConnection();//创建连接 Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE);/*创建会话,第一个参数标示是否使用事务,第二个表示自动通知,指收到消息后自动恢复消息中间件,中间件就会认为你收到了然后把消息删除,如果不是自动通知则意味可以重复接受消息。*/ MessageConsumer consumer = session.createConsumer(des); con.start();//通知消息中间件,准备就绪,可以分发消息了 Message message = consumer.receive(); if(message instanceof TextMessage){ TextMessage msg = (Textmessage)message; String text = msg.getText(); System.out.println(text); } con.close(); } }

 

  • 先起消费者会进入阻塞,直到生产者放入消息后,消费者取消息,然后退出
  • 队列中的消息只能接受一次,下次消费端接收会进入阻塞,直到有新消息进来

如果要改写为基于主题的 ,只需要修改Destination,改目标位主题就行

  • 先起生产者,由于没有预定(没有消费者监听),没有任何作用。所以需要先预定,再分发。
  • 先起消费者,消费者阻塞,直到对应目标中有生产者放入消息,可以有多个消费者。
  • 持久化订阅者:特殊的消费者,告诉主题,我一直订阅着,即使网络断开,消息服务器也记住所有持久化订阅者,如果有新消息,也会知道必定有人回来消费。

 

这里消费者,可以以另一种方式,监听器来完成消费消息,等于把消息当成一个事件处理,代码如下:

 

public class MyMessageListener implements MessageListener{ public void onMessage(Message message){ if(message instanceof TextMessage){ TextMessage msg = (TextMessage) message; String text; try{ text = msg.getText(); System.out.println(text); }catch(JMSException e){ e.printStackTrace(); } } } } public class Producer{ public static void main(String[] args)throws NamingException{ Context ctx = new InitialContext(); ConnectionFactory cf = (ConnectonFactory)ctx.lookup("ConnectionFactory");//名字在Jboss中缺省就叫ConnectionFactory Destination des = (Destination)ctx.lookup("queue/Testqueue");//查询目标 Connection con = cf。createConnection Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE MessageConsumer consumer = session.createConsumer(des); con.start(); // Message message = consumer.receive(); // if(message instanceof TextMessage){ // TextMessage msg = (Textmessage)message; // String text = msg.getText(); // System.out.println(text); // } // 注册消息监听器,他会单独起一个线程监听消息,主线程不会阻碍 consumer.setMessageListemer(new MyMessageListener()) //这里 就不能关闭连接了,因为监听器还在监听。 // con.close(); } }

 

 

在服务器中查看发送后在队列中缓存的消息

 

1、以jboss为例,在目标队列中,找到对应方法。

 EJB3学习笔记_Message-Driven Bean_第1张图片

 

该方法,返回所有在当前队列中被缓存的方法:

 

 

例子,当前队列中只有一条消息,如下:

 Header:消息头

 Body:消息体

 

 

 

 

消息的类型

 

主要有以下几类:

 EJB3学习笔记_Message-Driven Bean_第2张图片

 

 

 

 

进入正题了

 

Message-Driven Bean

 

 

1、A special EJB component that can receive JMS messages as well as other types of messages

2、Consumes messages from different destinations

3、MDB没有远程、本地业务接口。

4、与statless session bean 一样,是无状态的,可共享的,在容器中有共享池。 

5、对于所有厂家提供的消息驱动bean, 起码支持JMS。(也可以支持soap等)

     要支持JMS,那就要支持消息监听器(就是上面提到消费消息的第二种方法)

6、消息监听器的onMessage方法无返回值,也无排除异常,所以MDB也如此。

7、MDB是无状态的,不会负责维护用户的信息。

8、MDB是单线程。(EJB全是单线程的)

 

 

例子:

当消息到来时,容器会在共享池中找一个bean 进行处理,并把当前接受到得消息传递给他

这与之前自己处理消息有什么不同能?

1、我们不用考虑线程的问题了,MDB能处理消息大量的并发

2、能提供容器的种种服务,比如缺省提供的事务服务。

3、不过消息的顺序是没有保证的。

4、持久化订阅者:消费者肯定会再来,消息会缓存住等待消费者。

//mappedName在不同中间件服务器上意义不同,可能是jndi名。非必须 //activationConfig:激活配置。必须的 @MessageDriven(mappedName="jms/FirstMdb",activationConfig={ //通知类型,缺省EJB使用容器管理事务,这里声明无意义,去掉保留一样。 @ActivationConfigProperty(propertyName="acknowledgeMode",propertyValue="Auto-acknowledge"), //目标类型 @ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Queue"), //目标的JNDI名 @ActivationConfigProperty(propertyName="destination",propertyValue="queue/testQueue"),) }) public class FirstMdb implements MessageListener{ public void onMessage(Message message){ TextMessage msg = (TextMessage) message; String text; try{ text=mgs.getText(); System.out.println(text); }catch(JMSException e){ e.printStackTrace(); } } }

 

 

 

 

 

你可能感兴趣的:(bean,session,jboss,ejb,jms,消息中间件)