最近公司准备用Activemq进行消息的通知,并且是request-reply模式的,遇到一个问题:在生产者向队列发送消息的时候,如果队列满了,则需要向生产者发送一个消息通知,从而尽快给用户一个答复,免得耽误时间,由于本人从未接触过Activemq,只能一边学习,一边实践了。今天终于做出来了,将重要代码贴在此地,以免忘记。
applicationContext.xml的内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:annotation-config />
<context:component-scan base-package="****.******.***" />
<bean id="prefetchPolicy" class="org.apache.activemq.ActiveMQPrefetchPolicy">
<property name="queuePrefetch" value="1" />
</bean>
<!-- get ConnectionFctory from URI:tcp://localhost:61616 -->
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<constructor-arg value="tcp://localhost:61616" />
<property name="alwaysSyncSend" value="true" />
<property name="producerWindowSize" value="0" />
<property name="prefetchPolicy" ref="prefetchPolicy" />
</bean>
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
destroy-method="stop">
<property name="connectionFactory" ref="connectionFactory" />
<property name="maxConnections" value="10" />
<property name="maximumActiveSessionPerConnection" value="10" />
<property name="expiryTimeout" value="10" />
<property name="idleTimeout" value="0" />
<!-- <property name="timeBetweenExpirationCheckMillis" value="50" /> -->
</bean>
<bean id="classPathResource" class="org.springframework.core.io.ClassPathResource">
<constructor-arg value="activemq.xml" />
</bean>
<bean id="brokerFactory" class="org.apache.activemq.xbean.BrokerFactoryBean">
<constructor-arg ref="classPathResource" />
<property name="start" value="true" />
</bean>
<!-- queue for module demo -->
<bean id="queueDm" class="org.apache.activemq.command.ActiveMQQueue">
<property name="physicalName" value="queueDm" />
</bean>
<!-- N多 -->
<!-- <bean id="amqServer1" class="****.******.****.demo.amq.AMQServer" destroy-method="stop"> -->
<!-- <constructor-arg index="0" ref="pooledConnectionFactory" />connection factory -->
<!-- <constructor-arg index="1" ref="queueDm" />queue -->
<!-- <constructor-arg index="2" value="20" />thread core pool size -->
<!-- <constructor-arg index="3" value="30000" />thread pool thread keep alive time -->
<!-- <constructor-arg index="4" value="30" />concurrent task number -->
<!-- </bean> -->
<bean id="amqClient" class="****.******.****.demo.amq.AMQClient" scope="prototype">
<property name="pooledConnectionFactory" ref="pooledConnectionFactory" />
<property name="adminQueue" ref="queueDm" />
</bean>
<bean id="mbeanchecker" class="test.****.******.****.demo.amq.MBeanChecker" />
<bean id="messagesender" class="test.****.******.****.demo.amq.MessageSender">
<property name="client" ref="amqClient" />
</bean>
</beans>
activemq.xml配置文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd">
<!-- 定义了一个Broker,就是一个ActiveMQ的实例 -->
<amq:broker brokerName="demoBroker"
xmlns="http://activemq.apache.org/schema/core" useJmx="true"
persistent="false">
<amq:managementContext>
<amq:managementContext connectorPort="6161"
jmxDomainName="demoBrokerContext" connectorPath="/jmxrmi" />
</amq:managementContext>
<amq:systemUsage>
<amq:systemUsage sendFailIfNoSpace="true">
<amq:tempUsage>
<amq:tempUsage limit="0kb" />
</amq:tempUsage>
<amq:memoryUsage>
<amq:memoryUsage limit="10kb" />
</amq:memoryUsage>
<amq:storeUsage>
<amq:storeUsage limit="0kb" />
</amq:storeUsage>
</amq:systemUsage>
</amq:systemUsage>
<amq:destinationPolicy>
<amq:policyMap>
<amq:policyEntries>
<amq:policyEntry queue="queueDm" useCache="false"
memoryLimit="10kb" producerFlowControl="true">
<amq:pendingQueuePolicy>
<amq:vmQueueCursor />
</amq:pendingQueuePolicy>
</amq:policyEntry>
</amq:policyEntries>
</amq:policyMap>
</amq:destinationPolicy>
<amq:transportConnectors>
<transportConnector uri="tcp://localhost:61616" />
</amq:transportConnectors>
</amq:broker>
</beans>
消息生产者AMQClient.java代码:
package ****.******.****.demo.amq;
import java.util.Date;
import java.util.UUID;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.jms.pool.PooledSession;
import org.apache.activemq.pool.PooledConnection;
import org.apache.activemq.pool.PooledConnectionFactory;
public class AMQClient implements MessageListener {
private PooledConnectionFactory pooledConnectionFactory;
public PooledConnectionFactory getPooledConnectionFactory() {
return pooledConnectionFactory;
}
public void setPooledConnectionFactory(
PooledConnectionFactory pooledConnectionFactory) {
this.pooledConnectionFactory = pooledConnectionFactory;
}
private ActiveMQQueue adminQueue;
private MessageProducer producer;
private MessageConsumer consumer;
private Destination tempDest;
public ActiveMQQueue getAdminQueue() {
return adminQueue;
}
public void setAdminQueue(ActiveMQQueue adminQueue) {
this.adminQueue = adminQueue;
}
private PooledConnection pConnection;
private PooledSession pSession;
public void start() throws JMSException {
pConnection = (PooledConnection) pooledConnectionFactory.createConnection();
pConnection.start();
pSession = (PooledSession) pConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = pSession.createProducer(adminQueue);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
tempDest = pSession.createTemporaryQueue();
consumer = pSession.createConsumer(tempDest);
consumer.setMessageListener(this);
}
public void stop() throws JMSException {
producer.close();
consumer.close();
pSession.close();
pConnection.close();
}
public void request(String request) throws JMSException {
start();
System.out.println("Requesting: " + request);
ObjectMessage objectMessage = pSession.createObjectMessage();
objectMessage.setObject(request);
objectMessage.setJMSReplyTo(tempDest);
objectMessage.setJMSTimestamp(new Date().getTime());
String correlationId = UUID.randomUUID().toString();
objectMessage.setJMSCorrelationID(correlationId);
producer.send(objectMessage);
}
@Override
public void onMessage(Message message) {
try {
System.out.println(((ObjectMessage)message).getObject());
} catch (JMSException e) {
System.out.println(e.getMessage());
}
}
}
查看队列信息的工具类:MBeanChecker.java
package test.****.******.****.demo.amq;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import org.apache.activemq.broker.jmx.BrokerViewMBean;
import org.apache.activemq.broker.jmx.QueueViewMBean;
public class MBeanChecker {
public MBeanChecker() {
new Thread() {
public void run() {
try {
Thread.sleep(20000);
for (int i = 0; i < 10000; i++) {
Thread.sleep(1200);
check();
}
} catch (Exception e) {
e.printStackTrace();
}
};
}.start();
}
private void check() throws Exception {
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:6161/jmxrmi");
JMXConnector connector = JMXConnectorFactory.connect(url, null);
connector.connect();
MBeanServerConnection connection = connector.getMBeanServerConnection();
// 需要注意的是,这里的my-broker必须和定义broker的时候的名称相同
/**
* org.apache.activemq:BrokerName=localhost,Type=Broker
* 中的BrokerName与Type必须首字小写
* org.apache.activemq:brokerName=localhost,type=Broker 大写小敏感。。
*/
ObjectName name = new ObjectName("demoBrokerContext:brokerName=demoBroker,type=Broker");
BrokerViewMBean mBean = (BrokerViewMBean) MBeanServerInvocationHandler.newProxyInstance(connection, name, BrokerViewMBean.class, true);
System.out.println(mBean.getBrokerName());
for (ObjectName queueName : mBean.getQueues()) {
QueueViewMBean queueMBean = (QueueViewMBean) MBeanServerInvocationHandler.newProxyInstance(connection, queueName, QueueViewMBean.class, true);
System.out.println("\n------------------------------\n");
// States for queue
System.out.println("消息队列名称: --- " + queueMBean.getName());
// Size
System.out.println("队列中剩余的消息数目: --- " + queueMBean.getQueueSize());
// Number of consumers:
System.out.println("消费者数目: --- " + queueMBean.getConsumerCount());
// Number of dequeue:
System.out.println("出队列数目: ---" + queueMBean.getDequeueCount());
}
}
public static void main(String[] args) {
}
}
测试发送消息的类:MessageSender.java
package test.****.******.****.demo.amq;
import javax.jms.JMSException;
import org.springframework.web.context.ContextLoader;
import ****.******.****.demo.amq.AMQClient;
public class MessageSender {
private AMQClient client;
public AMQClient getClient() {
return client;
}
public void setClient(AMQClient client) {
this.client = client;
}
public MessageSender() {
new Thread() {
public void run() {
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
sendRequest();
};
}.start();
}
private void sendRequest() {
for (int i = 0; i < 5000; i++) {
try {
Thread.sleep(200);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
AMQClient client = (AMQClient) ContextLoader.getCurrentWebApplicationContext().getBean("amqClient");
client.request("TEST-REQUEST:" + i);
System.out.println("测试端发送消息: TEST-REQUEST:" + i);
} catch (JMSException e) {
System.err.println("jzf的发送端获取到的错误信息====================================" + e.getMessage());
break;
}
}
}
public static void main(String[] args) {
}
}