JMS实践-----------------浅谈JMS和MDB
在做JMS程序之前找了一些资源,总觉得不是很合适,要么讲的很理论化----理论描述过多,实际介绍不足,要么就是全是动手—缺少理论的深入。通过这几天的研究和动手,对JMS和MDB有了一个比较深刻的理解咯。
先从JMS程序谈起,首先,JMS和JDBC一样,是sun推出的一组API的集合,不同的厂商去实现这些接口。JMS的类型:queue和topic,这些的区别,也不再废话多说。
JMS的消息分为两种,一个是消息头,一个消息体。
一个JMS程序包括以下部分。一个是支持JMS的服务器,一个JMS的生产者,即向服务器发送消息,这个没有任何要求,可以是任何程序,包括Servlet,JSP,或者Java Application。
发送JMS消息,跟写通过JDBC向数据库做操作一样。首先要查找数据源,建立数据库连接。JMS程序也是一样。不过它是基于JNDI的方式,比如假如你想往JBOSS服务器发送JMS消息,你要这样像建立数据源一样,准备一个jndi.properties文件:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory-----基本不需要改变,设置在jboss/server/default/config/jndi下面。 java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces---同上 java.naming.provider.url=localhost:1099//localhost是服务器的地址,这里默认为本地 |
你可以把这个文件放到你的classpath下面,然后通过API去获得里面的内容,获得JNDI的Connection
MessageProducer messageProducer =null; QueueSession session = null; MessageObject msgobj= null; Properties prop = new Properties(); initialProperties(prop); InitialContext ctx = new InitialContext(prop); QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("ConnectionFactory"); Queue queue = (Queue) ctx.lookup("queue/haha"); //这里lookup的内容在queue-example-service.xml有定义jndi //这里的内容是一个JNDI上一个资源,以后可以把一个MDB制定为queue/haha, //假如没有MDB,则可以自己在Jboss建立一个资源,我是这样建立一个资源的。 //打开你的C:/TOOLS/jboss-4.2.2.GA/server/default/deploy/jms,找到jbossmq-destination-service.xml文件,在最后面加上 “<mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=haha"> <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends> </mbean>” 然后,就能在jboss里看到这个资源了。,假如是mdb的话,就不需要修改这个文件,而只需要你建立一个jboss.xml文件,把你的mdb对象和Queue绑定一下。jboss会自动建立新的Queue对象的 cnn = factory.createQueueConnection(); session = cnn.createQueueSession(false,//不需要事务 QueueSession.AUTO_ACKNOWLEDGE);//自动接收消息 ObjectMessage objmsg = session.createObjectMessage(); //objmsg.setObject((Serializable)msgobj); /* TextMessage msg = session.createTextMessage("This is the Message!");*/ //sender = session.createSender(queue); messageProducer =session.createProducer(queue); List data =new ArrayList(); //sender.send(msg); for(int i =0;i<10;i++){ msgobj = new MessageObject(); msgobj.setId("id is "+String.valueOf(i)); msgobj.setContent("How are you !This is message "+i); //sender.send(objmsg); System.out.println("Sending Message......+......"+i);
data.add(msgobj); } objmsg.setObject((Serializable) data); messageProducer.send(objmsg); System.out.println("Message sent successfully to remote queue."); |
|
这样,只要把jbossall-client.jar导入到你的工程的classpath下就可以运行这个程序。这个程序运行成功后,你可以看到刚才建立的MQ类型的队列里的消息
|
点击以后,看看该资源有那些消息
|
消息内容部分,
|
要想处理该消息,有两种办法,一个是编写一个简单的消费程序----消费程序可以任何形式的,JSP,servlet,Bean,但是还需要编写一个MessageListener对象,然后set到这个消费者程序里,这样就能处理JMS消息了
首先展示的MessageListener程序:
Public class MyListneer implements javax.jms.listener{
public void onMessage(Message recvMsg) { try { System.out.println("----------------"); System.out.println("Received message"); if(recvMsg instanceof ObjectMessage){ ObjectMessage msg2 = (ObjectMessage)recvMsg; Object obj =msg2.getObject(); List data =(List)obj; int j =data.size(); for(int i =0;i<j;i++){ MessageObject messageObject =(MessageObject) data.get(i); System.out.println("MessageObject message content: "+messageObject.getId()); } /*List list =(List)obj; for(Iterator iterator =list.iterator();iterator.hasNext();){ MessageObject mo =(MessageObject)iterator.next(); String cont =mo.getContent(); System.out.println(cont);
}*/ } System.out.print("OutputMessage: "+recvMsg);
System.out.println("----------------");
//recvMsg.clearBody(); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); mdc.setRollbackOnly(); } }
} |
然后是消费者程序:
public class JMSReceiver { /** * @param args */ public static void main(String[] args) { try{ QueueConnection cnn = null; QueueSession session = null; TextMessage msg = null; FileInputStream in = new FileInputStream("d:/test/jndi.properties"); Properties prop = new Properties(); prop.load(in); InitialContext ctx = new InitialContext(prop); Queue queue = (Queue) ctx.lookup("queue/haha"); //这里lookup的内容在queue-example-service.xml有定义jndi System.out.println(queue); QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup("ConnectionFactory"); cnn = factory.createQueueConnection(); session = cnn.createQueueSession(false,//不需要事务 QueueSession.AUTO_ACKNOWLEDGE);//自动接收消息 QueueReceiver receiver = session.createReceiver(queue); receiver.setMessageListener(new MyListener()); cnn.start(); }catch(Exception e){ e.printStackTrace(); }
} } |
当这个侦听程序被setter到消费者程序里以后,改侦听程序是一直在运行的,当再有新消息来的时候,会一直在处理。
这里需要特别说明的MDB程序,其实MDB本身是JMS体系的一部分,要不然sun推出这个特殊的EJB干吗?
编写MDB程序,其实就是在刚才的那个侦听程序上再多实现一个接口javax.ejb.MessageDrivenBean,这样就不需要再编写一个消费者程序去主动拿server上的消息了-----而是当服务器上有了消息以后,就会自动调用改MDB的onMessage方法----前提是你的MDB必须事先注册到server(注意必须是EJB的发布方式,要有ejb-jar.xml),可能还需要一个jboss.xml文件,把你的MDB注册在里面。
第一个ejb-jar.xml:
<message-driven id="MessageDriven_1"> <description><![CDATA[<!-- begin-xdoclet-definition -->]]></description>
<ejb-name>ExampleMDB</ejb-name>
<ejb-class>mdb.test.ExampleMDB</ejb-class>
<messaging-type>javax.jms.MessageListener</messaging-type> <transaction-type>Bean</transaction-type> <message-destination-type>javax.jms.Queue</message-destination-type> <activation-config> <activation-config-property> <activation-config-property-name>destinationType</activation-config-property-name> <activation-config-property-value>javax.jms.Queue</activation-config-property-value> </activation-config-property> <activation-config-property> <activation-config-property-name>acknowledgeMode</activation-config-property-name> <activation-config-property-value>Auto-acknowledge</activation-config-property-value> </activation-config-property> </activation-config>
</message-driven>
|
Jboss.xml:
<?xml version="1.0" encoding="UTF-8"?> <jboss> <enterprise-beans> <message-driven> <ejb-name>ExampleMDB</ejb-name> <destination-jndi-name>queue/exampleMDB</destination-jndi-name> </message-driven>
</enterprise-beans> </jboss>
|
这样就可以了。
再说部署,假如没有MDB程序,必须在jboss-destination-server.xml文件里添加一个queue或者topic的对象,比如说queue/haha, 而假如采用了MDB,择需要采取灵活的方式,在jboss里绑定一个MDB到Queue对象上。
<?xml version="1.0" encoding="UTF-8"?> <jboss> <enterprise-beans> <message-driven> <ejb-name>ExampleMDB</ejb-name> <destination-jndi-name>queue/exampleMDB</destination-jndi-name> </message-driven>
</enterprise-beans> </jboss> |
那么在JBosss启动的时候,可以看到由jboss新建好的这个” queue/exampleMDB”.客户端程序再连接这个建好的Queue。