Jboss中实现了HornetQ,这个应该是jms消息中间件
在 standalone-all.xml,我们能看到其默认的配置
<subsystemxmlns="urn:jboss:domain:messaging:1.2">
<hornetq-server>
<persistence-enabled>true</persistence-enabled>
<journal-file-size>102400</journal-file-size>
<journal-min-files>2</journal-min-files>
<connectors>(hornetq有connector和acceptor概念,connector和acceptor都有两种in-vm 和netty,只有同一种类型的connetor和acceptor才能联合使用,in-vm表明connetor和acceptor在同一个java虚拟机中,netty表示不在一个vm中)
…..
</connectors>
<acceptors>
….
</acceptors>
<security-settings>
…
</security-settings>
<address-settings>
<!--default for catchall-->
<address-settingmatch="#">(匹配任意队列)
<dead-letter-address>jms.queue.DLQ</dead-letter-address>(如果消息的重试处理次数超过了最大尝试次数,会被移入这个队列)
<expiry-address>jms.queue.ExpiryQueue</expiry-address>(如果消息过期了,会被移入这个队列)
<redelivery-delay>0</redelivery-delay>(重试处理的时间间隔,如果是0,就是立即重试)
<max-size-bytes>10485760</max-size-bytes>(队列最多可以存多少字节的数据)
<address-full-policy>BLOCK</address-full-policy>(如果队列满了,对新加入消息的处理策略)
<message-counter-history-day-limit>10</message-counter-history-day-limit>
</address-setting>
</address-settings>
<jms-connection-factories>
<connection-factoryname="InVmConnectionFactory">
<connectors>
<connector-refconnector-name="in-vm"/>
</connectors>
<entries>
<entryname="java:/ConnectionFactory"/>
</entries>
</connection-factory>
<connection-factoryname="RemoteConnectionFactory">
<connectors>
<connector-refconnector-name="netty"/>
</connectors>
<entries>
<entryname="java:jboss/exported/jms/RemoteConnectionFactory"/>
</entries>
</connection-factory>
<pooled-connection-factory name="hornetq-ra">(定义其resource adapter)
<transactionmode="xa"/>
<connectors>
<connector-refconnector-name="in-vm"/>
</connectors>
<entries>
<entryname="java:/JmsXA"/>
</entries>
</pooled-connection-factory>
</jms-connection-factories>
</hornetq-server>
</subsystem>
我们使用jms,只要在standalone.xml的hornetq-server定义中修改参数或者增加消息队列地址
然后实现相关发送消息和处理消息的代码就可以了
实例:
1. 新增一个队列地址为MyEventQueue
在standalone.xml 增加定义
a. 指定使用messaging module
<extensionmodule="org.jboss.as.messaging"/>
b. 增加hornetq-server定义,可以将standalone-full.xml中关于org.jboss.as.messaging subsystem 的定义拷贝过来
c. 增加队列定义
hornetq-server定义增加以下元素,因为前面hornetq-server中使用了dead letter 队列以及expire queue,所以在这里
也定义了这两个队列,我们实际使用的和业务相关的队列是MyEventsQueue
<jms-destinations>
<jms-queuename="DLQ">
<entryname="/queue/DLQ"/>
</jms-queue>
<jms-queuename="ExpiryQueue">
<entryname="/queue/ExpiryQueue"/>
</jms-queue>
<jms-queuename="MyEventsQueue">
<entryname="/queue/MyEventsQueue"/>
</jms-queue>
</jms-destinations>
d. 因为后续我们使用mdb来处理消息队列的消息,所以我们在<subsystem xmlns="urn:jboss:domain:ejb3:1.3">中增加如下的定义
指定其相关的resource adapter为hornetq-ra
<mdb>
<resource-adapter-refresource-adapter-name="hornetq-ra"/>
<bean-instance-pool-refpool-name="mdb-strict-max-pool"/>
</mdb>
这样mdb可以处理hornetq server发出的消息
e. 因为我们在hornetq server中指定了一些socket-binding,所以在<socket-binding-group>中我们得增加相关的定义
<socket-bindingname="messaging" port="5445"/>
<socket-bindingname="messaging-throughput" port="5455"/>
2. 定义一种event,这个event是普通类,需要扩展Serializable接口,表明其可以序列化
public class MyEvent implements Serializable {
private static final long serialVersionUID =-8851617570957121969L;
private String messageBody;
public MyEvent(Stringbody){
this.messageBody = body;
}
public String getMessageBody() {
return messageBody;
}
public voidsetMessageBody(String messageBody) {
this.messageBody = messageBody;
}
}
3. 实现一个ejb,调用这个ejb的notify方法,会给这个消息队列发送
public interface EventSender{
void notifyEvent();
}
@Stateless
@Remote(EventSender.class)
public class EventSenderBean implements EventSender {
private static String destination = "java:/queue/MyEventsQueue";
private static final Logger logger = LoggerFactory.getLogger("EventLog");
@Override
public void notifyEvent() {
QueueConnection queueConnection = null;
QueueSession queueSession = null;
Queue queue = null;
QueueSender publisher = null;
try
{
//TODO Auto-generatedmethod stub
InitialContext ctx = null;
ctx = new InitialContext();
//获得消息队列的connection factory
QueueConnectionFactory cf = (QueueConnectionFactory) ctx.lookup("java:/ConnectionFactory");
//获得对应消息队列
queue = (Queue) ctx.lookup(destination);
//使用connection 工厂创建connection,并启动
queueConnection = cf.createQueueConnection();
queueConnection.start();
//创建会话
queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
//创建sender
publisher = queueSession.createSender(queue);
publisher.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
//发送消息,发送消息应该不用每次都创建connection,会话和sender,应该可以使用已创建的这些对象
for(int i = 0 ; i < 10;i++){
MyEvent event = new MyEvent("event " + i );
logger.info("send message: "+event.getMessageBody());
final ObjectMessagemessage = queueSession.createObjectMessage(event);
publisher.send(message);
}
}catch(Exception e){
logger.error(e.getLocalizedMessage());
logger.info("errormessage",e.getStackTrace());
}finally{
if(queueConnection!=null){
try {
queueConnection.close();
} catch (JMSException e) {
// TODO Auto-generatedcatch block
logger.info("shutdownconnection error",e.getStackTrace());
} }} }}
4. 实现mdb,消费这个队列上的消息
import javax.ejb.MessageDriven;
import javax.ejb.ActivationConfigProperty;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import org.slf4j.*;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destination", propertyValue = "java:/queue/MyEventsQueue") })
public class EventConsumerMDB implements MessageListener{
private static final Logger logger = LoggerFactory.getLogger("EventLog");
@Override
public void onMessage(Messagemessage) {
if(message instanceof ObjectMessage){
try{
ObjectMessage receiveMessage =(ObjectMessage)message;
Object body =receiveMessage.getObject();
if(body instanceof MyEvent){
logger.info("receivemessage: " + ((MyEvent)body).getMessageBody());
}
}catch(Exception e){
logger.error(e.getMessage());
logger.info("consumemessage" , e);
}}}}
5.客户端调用ejb的notifyEvent方法发送消息