消息驱动bean(message driven bean)MDB--用于处理基于消息的组件
下面借用几张黎老师讲课的图片 很清晰 就直接上图了
队列方式 Queue 即点对点PTP 一个消息只能传递给一个接收者
环状方式 Topic 即pub/sub 发布/订阅 一条消息可以有多个接收方
对于jboss7中 默认的standalone中 是没有jms的配置的 但是standalone-full里面有jms的配置 所以将jboss-as-7.1.1.Finalstandaloneconfiguration 下的standalone-full.xml改为standalone.xml 即可 打开修改的文件 找到jms测试的queue、topic的目的地址的配置
<jms-destinations> <jms-queue name="testQueue"> <entry name="queue/test"/> <entry name="java:jboss/exported/jms/queue/test"/> </jms-queue> <jms-topic name="testTopic"> <entry name="topic/test"/> <entry name="java:jboss/exported/jms/topic/test"/> </jms-topic> </jms-destinations>
记住它的名字 一会在代码中要用
还有一个就是连接工厂
<jms-connection-factories> <connection-factory name="InVmConnectionFactory"> <connectors> <connector-ref connector-name="in-vm"/> </connectors> <entries> <entry name="java:/ConnectionFactory"/> </entries> </connection-factory> <connection-factory name="RemoteConnectionFactory"> <connectors> <connector-ref connector-name="netty"/> </connectors> <entries> <entry name="RemoteConnectionFactory"/> <entry name="java:jboss/exported/jms/RemoteConnectionFactory"/> </entries> </connection-factory> <pooled-connection-factory name="hornetq-ra"> <transaction mode="xa"/> <connectors> <connector-ref connector-name="in-vm"/> </connectors> <entries> <entry name="java:/JmsXA"/> </entries> </pooled-connection-factory> </jms-connection-factories>
好了 现在开始使用PTP方式产生消息
package com.undergrowth.hello.impl; import javax.annotation.Resource; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.jms.ConnectionFactory; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.QueueSession; import javax.jms.TextMessage; import com.undergrowth.hello.JmsMessProducer; /** * * @author Administrator * */ @Stateless @Remote(JmsMessProducer.class) public class JmsMessProducerBean implements JmsMessProducer { //注入连接工厂和目的地 @Resource(mappedName="java:/ConnectionFactory") private QueueConnectionFactory conFactory; @Resource(mappedName="java:/queue/test") private Destination destination; @Override public void send(String what) { // TODO Auto-generated method stub QueueConnection queueConnection=null; QueueSession session=null; try { //创建队列连接 queueConnection=conFactory.createQueueConnection(); session=queueConnection.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE); //创建消息提供者 MessageProducer producer=session.createProducer(destination); TextMessage message=session.createTextMessage(what); //发送消息 producer.send(message); System.out.println(JmsMessProducerBean.class+": 发送的消息为: "+message.getText()); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { session.close(); queueConnection.close(); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
远程接口
package com.undergrowth.hello; /** * 消息的发送者 * @author Administrator * */ public interface JmsMessProducer { public void send(String what); }
使用MDB注册到JBOSS中 接收PTP消息
package com.undergrowth.hello.impl; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; @MessageDriven(activationConfig={ @ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Queue"), @ActivationConfigProperty(propertyName="destination",propertyValue="java:/queue/test") }) public class JmsMessageConsumer implements MessageListener { @Override public void onMessage(Message msg) { // TODO Auto-generated method stub TextMessage message=(TextMessage) msg; try { System.out.println(JmsMessageConsumer.class+": 接收到消息为: "+message.getText()); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
再看另一种方式 Topic pub/sub
package com.undergrowth.hello.impl; import javax.annotation.Resource; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageProducer; import javax.jms.TextMessage; import javax.jms.TopicConnection; import javax.jms.TopicConnectionFactory; import javax.jms.TopicSession; import com.undergrowth.hello.JmsMessTopicProducer; @Stateless @Remote(JmsMessTopicProducer.class) public class JmsMessTopicProducerBean implements JmsMessTopicProducer{ //注入连接工厂和目的地 @Resource(mappedName="java:/ConnectionFactory") private TopicConnectionFactory conFactory; @Resource(mappedName="java:/topic/test") private Destination destination; @Override public void send(String what) { // TODO Auto-generated method stub TopicConnection connection=null; TopicSession session=null; try { connection=conFactory.createTopicConnection(); session=connection.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE); MessageProducer producer=session.createProducer(destination); TextMessage message=session.createTextMessage(what); producer.send(message); System.out.println(JmsMessTopicProducerBean.class+" 发送的消息为: "+what); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { session.close(); connection.close(); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
远程接口
package com.undergrowth.hello; public interface JmsMessTopicProducer extends JmsMessProducer{ }
使用多个消息驱动bean 来接收pub/sub 消息
package com.undergrowth.hello.impl; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; @MessageDriven(activationConfig={ @ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Topic"), @ActivationConfigProperty(propertyName="destination",propertyValue="java:/topic/test") }) public class JmsMessTopicConsumer implements MessageListener{ @Override public void onMessage(Message msg) { // TODO Auto-generated method stub TextMessage message=(TextMessage) msg; try { System.out.println(JmsMessTopicConsumer.class+" 接收到的消息为: "+message.getText()); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }
另外一个
package com.undergrowth.hello.impl; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.TextMessage; @MessageDriven(activationConfig={ @ActivationConfigProperty(propertyName="destinationType",propertyValue="javax.jms.Topic"), @ActivationConfigProperty(propertyName="destination",propertyValue="java:/topic/test") }) public class JmsMessTopicConsumerOther implements MessageListener{ @Override public void onMessage(Message msg) { // TODO Auto-generated method stub TextMessage message=(TextMessage) msg; try { System.out.println(JmsMessTopicConsumerOther.class+" 接收到的消息为: "+message.getText()); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }
好了 服务端写好了 打包发布 ant 的build.xml文件
<?xml version="1.0" encoding="UTF-8"?> <!-- ================================================ --> <!-- Sample buildfile for jar components --> <!-- --> <!-- ================================================ --> <project name="HelloWorld" basedir="."> <!-- 定义属性 --> <property name="src.dir" value="${basedir}src" /> <property environment="env" /> <property name="jboss.home" value="${env.JBOSS_HOME}"/> <property name="jboss.server.home" value="standalone" /> <property name="dep" value="deployments" /> <property name="build.dir" value="${basedir}uild" /> <path id="build.classpath"> <fileset dir="${basedir}lib"> <include name="*.jar" /> </fileset> <pathelement location="${build.dir}" /> </path> <!-- - - - - - - - - - - - - - --> <!-- target: init --> <!-- - - - - - - - - - - - - - --> <target name="init"> <delete dir="${build.dir}"></delete> <mkdir dir="${build.dir}"></mkdir> </target> <!-- ========================= --> <!-- target: compile --> <!-- ========================= --> <target name="compile" depends="init" description="--> compile this component" > <javac srcdir="${src.dir}" destdir="${build.dir}" includes="com/**"> <classpath refid="build.classpath" /> </javac> </target> <!-- 打包 --> <target name="ejbjar" depends="compile" description="打包ejb"> <jar jarfile="${basedir}${ant.project.name}.jar"> <fileset dir="${build.dir}"> <include name="**/*.class"></include> </fileset> <metainf dir="${src.dir}META-INF"></metainf> </jar> </target> <!-- 部署 --> <target name="delopy" depends="ejbjar" description="部署ejb"> <copy file="${basedir}${ant.project.name}.jar" todir="${jboss.home}${jboss.server.home}${dep}" /> </target> <!-- 卸载ejb --> <target name="undeploy" description="卸载ejb"> <delete file="${jboss.home}${jboss.server.home}${dep}${ant.project.name}.jar"></delete> </target> <!-- 打包接口 --> <target name="package_inter" depends="compile" description="打包接口"> <jar jarfile="${basedir}${ant.project.name}Interface.jar"> <fileset dir="${build.dir}"> <exclude name="**/impl/*.class"></exclude> </fileset> </jar> </target> </project>
jboss 控制台
22:04:59,587 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-3) JNDI bindings for session bean named JmsMessProducerBean in deployment unit deployment "HelloWorld.jar" are as follows: java:global/HelloWorld/JmsMessProducerBean!com.undergrowth.hello.JmsMessProducer java:app/HelloWorld/JmsMessProducerBean!com.undergrowth.hello.JmsMessProducer java:module/JmsMessProducerBean!com.undergrowth.hello.JmsMessProducer java:jboss/exported/HelloWorld/JmsMessProducerBean!com.undergrowth.hello.JmsMessProducer java:global/HelloWorld/JmsMessProducerBean java:app/HelloWorld/JmsMessProducerBean java:module/JmsMessProducerBean
22:04:59,576 INFO [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-3) JNDI bindings for session bean named JmsMessTopicProducerBean in deployment unit deployment "HelloWorld.jar" are as follows: java:global/HelloWorld/JmsMessTopicProducerBean!com.undergrowth.hello.JmsMessTopicProducer java:app/HelloWorld/JmsMessTopicProducerBean!com.undergrowth.hello.JmsMessTopicProducer java:module/JmsMessTopicProducerBean!com.undergrowth.hello.JmsMessTopicProducer java:jboss/exported/HelloWorld/JmsMessTopicProducerBean!com.undergrowth.hello.JmsMessTopicProducer java:global/HelloWorld/JmsMessTopicProducerBean java:app/HelloWorld/JmsMessTopicProducerBean java:module/JmsMessTopicProducerBean
‘
第三方客户端测试
queue测试
package com.undergrowth.ejb3.client; import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import com.undergrowth.hello.HelloWorldLocal; import com.undergrowth.hello.JmsMessProducer; public class JmsClient { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub try { JmsMessProducer messProducer=lookupRemoteHelloWorldBean(); messProducer.send("jms文本消息,明天又要上班了!!!"); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static JmsMessProducer lookupRemoteHelloWorldBean() throws NamingException { final Hashtable jndiProperties = new Hashtable(); jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); final Context context = new InitialContext(jndiProperties); // The app name is the application name of the deployed EJBs. This is typically the ear name // without the .ear suffix. However, the application name could be overridden in the application.xml of the // EJB deployment on the server. // Since we haven't deployed the application as a .ear, the app name for us will be an empty string final String appName = ""; // This is the module name of the deployed EJBs on the server. This is typically the jar name of the // EJB deployment, without the .jar suffix, but can be overridden via the ejb-jar.xml // In this example, we have deployed the EJBs in a jboss-as-ejb-remote-app.jar, so the module name is // jboss-as-ejb-remote-app final String moduleName = "HelloWorld"; // AS7 allows each deployment to have an (optional) distinct name. We haven't specified a distinct name for // our EJB deployment, so this is an empty string final String distinctName = ""; // The EJB name which by default is the simple class name of the bean implementation class final String beanName = "JmsMessProducerBean"; // the remote view fully qualified class name // final String viewClassName = HelloWorldRemote.class.getName(); final String viewClassName = JmsMessProducer.class.getName(); // let's do the lookup return (JmsMessProducer) context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName); } }
控制台
22:10:18,816 INFO [stdout] (EJB default - 3) class com.undergrowth.hello.impl.JmsMessProducerBean: 发送的消息为: jms文本消息,明天又要上班了!!! 22:10:19,226 INFO [stdout] (Thread-162 (HornetQ-client-global-threads-28566125)) class com.undergrowth.hello.impl.JmsMessageConsumer: 接收到消息为: jms文本消息,明天又要上班了!!!
看下jboss的管理控制台
队列消息添加1 运行一次客户端 加一次
topic方式 测试
package com.undergrowth.ejb3.client; import java.util.Hashtable; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import com.undergrowth.hello.HelloWorldLocal; import com.undergrowth.hello.JmsMessProducer; import com.undergrowth.hello.JmsMessTopicProducer; public class JmsTopicClient { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub try { JmsMessProducer messProducer=lookupRemoteHelloWorldBean(); messProducer.send("jms的topic方式文本消息,明天又要上班了!!!"); } catch (NamingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static JmsMessTopicProducer lookupRemoteHelloWorldBean() throws NamingException { final Hashtable jndiProperties = new Hashtable(); jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); final Context context = new InitialContext(jndiProperties); // The app name is the application name of the deployed EJBs. This is typically the ear name // without the .ear suffix. However, the application name could be overridden in the application.xml of the // EJB deployment on the server. // Since we haven't deployed the application as a .ear, the app name for us will be an empty string final String appName = ""; // This is the module name of the deployed EJBs on the server. This is typically the jar name of the // EJB deployment, without the .jar suffix, but can be overridden via the ejb-jar.xml // In this example, we have deployed the EJBs in a jboss-as-ejb-remote-app.jar, so the module name is // jboss-as-ejb-remote-app final String moduleName = "HelloWorld"; // AS7 allows each deployment to have an (optional) distinct name. We haven't specified a distinct name for // our EJB deployment, so this is an empty string final String distinctName = ""; // The EJB name which by default is the simple class name of the bean implementation class final String beanName = "JmsMessTopicProducerBean"; // the remote view fully qualified class name // final String viewClassName = HelloWorldRemote.class.getName(); final String viewClassName = JmsMessTopicProducer.class.getName(); // let's do the lookup return (JmsMessTopicProducer) context.lookup("ejb:" + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName); } }
控制台
22:13:45,928 INFO [stdout] (EJB default - 5) class com.undergrowth.hello.impl.JmsMessTopicProducerBean 发送的消息为: jms的topic方式文本消息,明天又要上班了!!! 22:13:45,931 INFO [stdout] (Thread-170 (HornetQ-client-global-threads-28566125)) class com.undergrowth.hello.impl.JmsMessTopicConsumerOther 接收到的消息为: jms的topic方式文本消息,明天又要上班了!!! 22:13:45,938 INFO [stdout] (Thread-174 (HornetQ-client-global-threads-28566125)) class com.undergrowth.hello.impl.JmsMessTopicConsumer 接收到的消息为: jms的topic方式文本消息,明天又要上班了!!!
两个接收者都收到消息了
jboss管理界面
好了
参看文档:
http://my.oschina.net/zhaoqian/blog/90796
http://dujianmeng.iteye.com/blog/1552685
记录学习的脚步