项目需要使用activemq 来做消息总线,刚开始看了下activemq in action 字体是在不好看,草草看完了,就动手下了个实现sender和receiver ,一般实现了就OK了,但是我实现以后,他虽然正常接收消息,但是不确认消息,很奇怪,想想这么牛XX的消息中间件,这么大的bug ,肯定不可能,然后就想着哪里肯定搞错了吧,结果继续学习查资料,功夫不负有心人啊,给解决了。废话不说了,开始吧。
首先 消息发送这边没什么好说的,可以查询一些文档,了解一些参数的设定。一会给出例子。
然后就是坑爹的接收消息:
1 消息接收有两种方式,
一种是直接使用consumer.setMessageListener(**)这个方法,设置监听器。他是阻塞式的,一直监听整个消息Queue ,
另一种是 直接consumer.receive(timeout); 直接返回消息Message ,你可以直接对消息进行处理。不是阻塞式的。
2 我遇到的问题在这里
Session session = connection.createSession(Boolean.FALSE,
Session.AUTO_ACKNOWLEDGE);
看见后面两个参数了没。
有两种情况:
1 当createSession第一个参数为true时,表示创建的session被标记为transactional的,确认消息就通过确认和校正来自动地处理,第二个参数应该是没用的。
--这句话抄别人的,没看懂
2 当createSession的第一个参数为false时,表示创建的session没有标记为transactional,此时有三种用于消息确认的选项:
**AUTO_ACKNOWLEDGE session将自动地确认收到的一则消息;
**CLIENT_ACKNOWLEDGE 客户端程序将确认收到的一则消息,调用这则消息的确认方法;
**DUPS_OK_ACKNOWLEDGE 这个选项命令session“懒散的”确认消息传递,可以想到,这将导致消息提供者传递的一些复制消息可能出错。
我的问题一直设置的true ,坑爹的是在http://localhost:8161/admin/browse.jsp?JMSDestination=File_UP_001这里看的时候总是pending message 而且他的Redelivered是true(也就是已经接收到了消息),一头雾水。
将true修改为false ,使用自动确认的Session.AUTO_ACKNOWLEDGE方式,结果一次性就问题就好了。
3 有两种方式NON_PERSISTENT、PERSISTENT
MS有两种消息传递方式。标记为NON_PERSISTENT的消息最多传递一次,而标记为PERSISTENT的消息将使用暂存后再转发的机理投递。如果一个JMS服务离线,那么持久性消息不会丢失,但是得等到这个服务恢复联机的时候才会被传递。所以默认的消息传递方式是非持久性的,虽然使用非持久性消息可能降低内存和需要的存储器,但这种传递方式只有当你不需要接收所有消息时才使用。
代码:JmsSender.java
package com.gzhdi.bus;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
* 消息的生产者(发送者)
*
*/
public class JmsSender
{
private static Connection connection = null;
private static ConnectionFactory connectionFactory = null;
private static JmsSender sender=null;
private static String FILE_UP_QUEUE_NAME="File_UP_001";
private static String MQ_USER=ActiveMQConnection.DEFAULT_USER;
//TODO 应该加密的
private static String MQ_PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD;
private JmsSender()
{
//initial the upper var
}
public boolean send(Msg msg) throws JMSException
{
if (connectionFactory == null)
{
// ConnectionFactory :连接工厂,JMS 用它创建连接
connectionFactory = new ActiveMQConnectionFactory(
MQ_USER,
MQ_PASSWORD,
"tcp://localhost:61616");
// JMS 客户端到JMS Provider 的连接
connection = connectionFactory.createConnection();
connection.start();
}
// Session: 一个发送或接收消息的线程
Session session = connection.createSession(Boolean.TRUE,
Session.AUTO_ACKNOWLEDGE);
// Destination :消息的目的地;消息发送给谁.
Destination destination = session.createQueue("File_UP_001");
// MessageProducer:消息生产者
MessageProducer producer = session.createProducer(destination);
// 设置不持久化
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// 发送一条消息
ObjectMessage object = session.createObjectMessage();
object.setObject(msg);
producer.send(object);
session.commit();
//connection.close();
System.out.println("commit Ok");
return true;
}
/**
* 得到一个实体
* @return JmsSender
* @author yinlei |2012-10-30 下午6:55:30
* @version 0.1
*/
public static JmsSender getInstance()
{
if(sender==null)
{
sender=new JmsSender();
}
return sender;
}
}
JmsReceiver.java
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.log4j.Logger;
/**
* 消息的消费者(接受者)
*
*/
public class JmsReceiver implements MessageListener, Runnable
{
private static Logger logger = Logger.getLogger(JmsReceiver.class);
public void run()
{
startConsumer();
}
public void startConsumer()
{
try
{
// ConnectionFactory :连接工厂,JMS 用它创建连接
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(
ActiveMQConnection.DEFAULT_USER,
ActiveMQConnection.DEFAULT_PASSWORD,
"tcp://localhost:61616");
// JMS 客户端到JMS Provider 的连接
Connection connection;
connection = connectionFactory.createConnection();
connection.start();
// Session: 一个发送或接收消息的线程
// 切记 ,这里的只有是false ,第二个参数才管用
Session session = connection.createSession(Boolean.FALSE,
Session.AUTO_ACKNOWLEDGE);
// Destination :消息的目的地;消息发送给谁.
Destination destination = session.createQueue("File_UP_001");
// 消费者,消息接收者
MessageConsumer consumer = session.createConsumer(destination);
consumer.setMessageListener(this);
} catch (JMSException e)
{
logger.error("Consumer error !!!",e);
e.printStackTrace();
}
}
// 对消息进行监听处理
public void onMessage(Message message)
{
FileMsg fm = null;
try
{
if (message.getJMSRedelivered() != true)
{
fm = (FileMsg) ((ObjectMessage) message).getObject();
if(fm.process())
{
logger.info("消息ObjectID:" +fm.getObjectID()+"处理完毕" );
}
}
} catch (JMSException e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
JmsReceiver jms=new JmsReceiver();
new Thread(jms).start();
}
}
消息体:
public class FileMsg
{
private static final long serialVersionUID = -518929429090930161L;
//应用ID
private String appID;
//objectID
private String objectID;
//文件路径
private String path;
public boolean process()
{
System.out.println("create a objectid objecID:"+objectID);
return true;
}
public String getAppID()
{
return appID;
}
public void setAppID(String appID)
{
this.appID = appID;
}
public String getObjectID()
{
return objectID;
}
public void setObjectID(String objectID)
{
this.objectID = objectID;
}
public String getPath()
{
return path;
}
public void setPath(String path)
{
this.path = path;
}
}
参考:http://riddickbryant.iteye.com/blog/441890