消息驱动bean(message driven bean)MDB--用于处理基于消息的组件
下面借用几张黎老师讲课的图片 很清晰 就直接上图了
队列方式 Queue 即点对点PTP 一个消息只能传递给一个接收者
环状方式 Topic 即pub/sub 发布/订阅 一条消息可以有多个接收方
对于jboss7中 默认的standalone中 是没有jms的配置的 但是standalone-full里面有jms的配置 所以将jboss-as-7.1.1.Final\standalone\configuration 下的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+":\t发送的消息为:\t"+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+":\t接收到消息为:\t"+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+"\t 发送的消息为:\t"+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+"\t 接收到的消息为:\t"+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+"\t 接收到的消息为:\t"+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}\build" />
<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
记录学习的脚步