1。 首先先引入相关的lib包,重点需引用activemq-client-5.8.0.jar,activemq-core-5.7.0.jar,activemq-pool-5.8.0.jar,activemq-protobuf-1.1.jar等包,其他包
自行配置。
2。 一些公共工具类的代码:
JMSProducer.java
package com.ffcs.icity.jms;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.pool.PooledConnectionFactory;
/**
* JMS消息生产者
* @author linwei
*
*/
public class JMSProducer implements ExceptionListener{
//设置连接的最大连接数
public final static int DEFAULT_MAX_CONNECTIONS=5;
private int maxConnections = DEFAULT_MAX_CONNECTIONS;
//设置每个连接中使用的最大活动会话数
private int maximumActiveSessionPerConnection = DEFAULT_MAXIMUM_ACTIVE_SESSION_PER_CONNECTION;
public final static int DEFAULT_MAXIMUM_ACTIVE_SESSION_PER_CONNECTION=300;
//线程池数量
private int threadPoolSize = DEFAULT_THREAD_POOL_SIZE;
public final static int DEFAULT_THREAD_POOL_SIZE=50;
//强制使用同步返回数据的格式
private boolean useAsyncSendForJMS = DEFAULT_USE_ASYNC_SEND_FOR_JMS;
public final static boolean DEFAULT_USE_ASYNC_SEND_FOR_JMS=true;
//是否持久化消息
private boolean isPersistent = DEFAULT_IS_PERSISTENT;
public final static boolean DEFAULT_IS_PERSISTENT=true;
//连接地址
private String brokerUrl;
private String userName;
private String password;
private ExecutorService threadPool;
private PooledConnectionFactory connectionFactory;
public JMSProducer(String brokerUrl, String userName, String password) {
this(brokerUrl, userName, password, DEFAULT_MAX_CONNECTIONS, DEFAULT_MAXIMUM_ACTIVE_SESSION_PER_CONNECTION, DEFAULT_THREAD_POOL_SIZE, DEFAULT_USE_ASYNC_SEND_FOR_JMS, DEFAULT_IS_PERSISTENT);
}
public JMSProducer(String brokerUrl, String userName, String password, int maxConnections, int maximumActiveSessionPerConnection, int threadPoolSize,boolean useAsyncSendForJMS, boolean isPersistent) {
this.useAsyncSendForJMS = useAsyncSendForJMS;
this.isPersistent = isPersistent;
this.brokerUrl = brokerUrl;
this.userName = userName;
this.password = password;
this.maxConnections = maxConnections;
this.maximumActiveSessionPerConnection = maximumActiveSessionPerConnection;
this.threadPoolSize = threadPoolSize;
init();
}
private void init() {
//设置JAVA线程池
this.threadPool = Executors.newFixedThreadPool(this.threadPoolSize);
//ActiveMQ的连接工厂
ActiveMQConnectionFactory actualConnectionFactory = new ActiveMQConnectionFactory(this.userName, this.password, this.brokerUrl);
actualConnectionFactory.setUseAsyncSend(this.useAsyncSendForJMS);
//Active中的连接池工厂
this.connectionFactory = new PooledConnectionFactory(actualConnectionFactory);
this.connectionFactory.setCreateConnectionOnStartup(true);
this.connectionFactory.setMaxConnections(this.maxConnections);
this.connectionFactory.setMaximumActiveSessionPerConnection(this.maximumActiveSessionPerConnection);
}
/**
* 执行发送消息的具体方法
* @param queue
* @param map
*/
public void send(final String queue, final Map map) {
//直接使用线程池来执行具体的调用
this.threadPool.execute(new Runnable(){
@Override
public void run() {
try {
sendMsg(queue,map);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* 真正的执行消息发送
* @param queue
* @param map
* @throws Exception
*/
private void sendMsg(String queue, Map map) throws Exception {
Connection connection = null;
Session session = null;
try {
//从连接池工厂中获取一个连接
connection = this.connectionFactory.createConnection();
/*createSession(boolean transacted,int acknowledgeMode)
transacted - indicates whether the session is transacted acknowledgeMode - indicates whether the consumer or the client
will acknowledge any messages it receives; ignored if the session is transacted.
Legal values are Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, and Session.DUPS_OK_ACKNOWLEDGE.
*/
//false 参数表示 为非事务型消息,后面的参数表示消息的确认类型
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
//Destination is superinterface of Queue
//PTP消息方式
Destination destination = session.createQueue(queue);
//Creates a MessageProducer to send messages to the specified destination
MessageProducer producer = session.createProducer(destination);
//set delevery mode
producer.setDeliveryMode(this.isPersistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);
//map convert to javax message
Message message = getMessage(session, map);
producer.send(message);
} finally {
closeSession(session);
closeConnection(connection);
}
}
private Message getMessage(Session session, Map map) throws JMSException {
MapMessage message = session.createMapMessage();
if (map != null && !map.isEmpty()) {
Set keys = map.keySet();
for (String key : keys) {
message.setObject(key, map.get(key));
}
}
return message;
}
private void closeSession(Session session) {
try {
if (session != null) {
session.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void closeConnection(Connection connection) {
try {
if (connection != null) {
connection.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onException(JMSException e) {
e.printStackTrace();
}
}
package com.ffcs.icity.jms;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.ActiveMQPrefetchPolicy;
/**
* JMS消息消费者
* @author linwei
*
*/
public class JMSConsumer implements ExceptionListener {
//队列预取策略
private int queuePrefetch=DEFAULT_QUEUE_PREFETCH;
public final static int DEFAULT_QUEUE_PREFETCH=10;
private String brokerUrl;
private String userName;
private String password;
private MessageListener messageListener;
private Connection connection;
private Session session;
//队列名
private String queue;
/**
* 执行消息获取的操作
* @throws Exception
*/
public void start() throws Exception {
//ActiveMQ的连接工厂
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory(this.userName, this.password, this.brokerUrl);
connection = connectionFactory.createConnection();
//activeMQ预取策略
ActiveMQPrefetchPolicy prefetchPolicy = new ActiveMQPrefetchPolicy();
prefetchPolicy.setQueuePrefetch(queuePrefetch);
((ActiveMQConnection) connection).setPrefetchPolicy(prefetchPolicy);
connection.setExceptionListener(this);
connection.start();
//会话采用非事务级别,消息到达机制使用自动通知机制
session = connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue(this.queue);
MessageConsumer consumer = session.createConsumer(destination);
consumer.setMessageListener(this.messageListener);
}
/**
* 关闭连接
*/
public void shutdown(){
try {
if (session != null) {
session.close();
session=null;
}
if (connection != null) {
connection.close();
connection=null;
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onException(JMSException e) {
e.printStackTrace();
}
public String getBrokerUrl() {
return brokerUrl;
}
public void setBrokerUrl(String brokerUrl) {
this.brokerUrl = brokerUrl;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getQueue() {
return queue;
}
public void setQueue(String queue) {
this.queue = queue;
}
public MessageListener getMessageListener() {
return messageListener;
}
public void setMessageListener(MessageListener messageListener) {
this.messageListener = messageListener;
}
public int getQueuePrefetch() {
return queuePrefetch;
}
public void setQueuePrefetch(int queuePrefetch) {
this.queuePrefetch = queuePrefetch;
}
}
package com.ffcs.icity.jms;
import javax.jms.Message;
/**
* 提供消息操作的回调接口
* @author linwei
*
*/
public interface MessageHandler {
/**
* 消息回调提供的调用方法
* @param message
*/
public void handle(Message message);
}
package com.ffcs.icity.jms;
import java.util.concurrent.ExecutorService;
import javax.jms.Message;
import javax.jms.MessageListener;
/**
* 消息消费者中使用的多线程消息监听服务
* @author linwei
*
*/
public class MultiThreadMessageListener implements MessageListener {
//默认线程池数量
public final static int DEFAULT_HANDLE_THREAD_POOL=10;
//最大的处理线程数.
private int maxHandleThreads;
//提供消息回调调用接口
private MessageHandler messageHandler;
private ExecutorService handleThreadPool;
public MultiThreadMessageListener(MessageHandler messageHandler){
this(DEFAULT_HANDLE_THREAD_POOL, messageHandler);
}
public MultiThreadMessageListener(int maxHandleThreads,MessageHandler messageHandler){
this.maxHandleThreads=maxHandleThreads;
this.messageHandler=messageHandler;
//支持阻塞的固定大小的线程池(自行手动创建的)
this.handleThreadPool = new FixedAndBlockedThreadPoolExecutor(this.maxHandleThreads);
}
/**
* 监听程序中自动调用的方法
*/
@Override
public void onMessage(final Message message) {
//使用支持阻塞的固定大小的线程池来执行操作
this.handleThreadPool.execute(new Runnable() {
public void run() {
try {
MultiThreadMessageListener.this.messageHandler.handle(message);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
package com.ffcs.icity.jms;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 支持阻塞的固定大小的线程池
* @author linwei
*
*/
public class FixedAndBlockedThreadPoolExecutor extends ThreadPoolExecutor {
//一个可重入的互斥锁 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
//使用 lock 块来调用 try,在之前/之后的构造中
private ReentrantLock lock = new ReentrantLock();
private Condition condition = this.lock.newCondition();
public FixedAndBlockedThreadPoolExecutor(int size) {
super(size, size, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue());
}
/**
* 当线程池中没有空闲线程时,会挂起此方法的调用线程.直到线程池中有线程有空闲线程.
*/
@Override
public void execute(Runnable command) {
//进行同步锁定
this.lock.lock();
super.execute(command);
try {
//如果线程池的数量已经达到最大线程池的数量,则进行挂起操作
if (getPoolSize() == getMaximumPoolSize()) {
this.condition.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
this.lock.unlock();
}
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
try {
this.lock.lock();
this.condition.signal();
} finally {
this.lock.unlock();
}
}
}
3. 调用例子说明:
生产者调用代码,JMSProducerTest.java
package com.ffcs.icity.test;
import java.util.HashMap;
import java.util.Map;
import com.ffcs.icity.jms.JMSProducer;
public class JMSProducerTest {
public static void main(String[] args) {
locationTest();
System.out.println("over.");
}
private static void locationTest() {
//** JMSProducer 可以设置成全局的静态变量,只需实例化一次即可使用,禁止循环重复实例化JMSProducer(因为其内部存在一个线程池)
//支持openwire协议的默认连接为 tcp://localhost:61616,支持 stomp协议的默认连接为tcp://localhost:61613。
//tcp和nio的区别
//nio://localhost:61617 以及 tcp://localhost:61616均可在 activemq.xml配置文件中进行配置
JMSProducer producer = new JMSProducer("nio://localhost:61617", "system", "manager");
Map map = new HashMap();
map.put("id", "1");
map.put("name", "sss1113333");
map.put("password", "password");
producer.send("test", map);
}
}
package com.ffcs.icity.test;
import javax.jms.MapMessage;
import javax.jms.Message;
import com.ffcs.icity.jms.JMSConsumer;
import com.ffcs.icity.jms.MessageHandler;
import com.ffcs.icity.jms.MultiThreadMessageListener;
public class JMSConsumerTest {
public static void main(String[] args) throws Exception {
//** JMSConsumer 可以设置成全局的静态变量,只需实例化一次即可使用,禁止循环重复实例化JMSConsumer(因为其内部存在一个线程池)
JMSConsumer consumer = new JMSConsumer();
consumer.setBrokerUrl("tcp://localhost:61616");
consumer.setQueue("test");
consumer.setUserName("system");
consumer.setPassword("manager");
consumer.setQueuePrefetch(500);
consumer.setMessageListener(new MultiThreadMessageListener(50,new MessageHandler() {
public void handle(Message message) {
try {
System.out.println("name is " + ((MapMessage)message).getString("name"));
Thread.sleep(5000);
} catch (Exception e) {
e.printStackTrace();
}
}
}));
consumer.start();
// Thread.sleep(5000);
// consumer.shutdown();
}
}