项目需要使用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方式,结果一次性就问题就好了。

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;
	}
	
}