HornetQ是一个支持集群和多种协议,可嵌入、高性能的异步消息系统。HornetQ完全支持JMS,HornetQ不但支持JMS1.1 API同时也定义属于自己的消息API,这可以最大限度的提升HornetQ的性能和灵活性。还支持RESTful API、STOMP(Stomp的客户端可以用多种编程语言来实现
)、AMQP(HornetQ will shortly be implementing AMQP )。
用途:松散地联系各系统,不用受其它服务器的制约,有效的减少线程Block的时间. 不同于RPC , 采用的Request/Reponse 的方式.
IP=`/sbin/ip a |grep 'inet '|awk -F'/' '{print $1}'|awk '{print $2}'|grep -v 127.0.0.1|head -1` export CLUSTER_PROPS="-Dhornetq.remoting.netty.host=$IP -Djnp.host=$IP" echo $CLUSTER_PROPS sh run.sh &
public void sendToQueue(String destinationName,Serializable payload) throws Exception { InitialContext ic = new InitialContext(); ConnectionFactory cf = (ConnectionFactory)ic.lookup("/ConnectionFactory"); Queue queue = (Queue)ic.lookup(destinationName); Connection connection = cf.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer publisher = session.createProducer(queue); connection.start(); ObjectMessage message = session.createObjectMessage(payload); message.setObject(payload); publisher.send(message); if (connection != null) { connection.close(); } } @TransactionAttribute(value = TransactionAttributeType.REQUIRED) public void onMessage(Message message) { ObjectMessage obj = (ObjectMessage) message; try { Serializable ser = obj.getObject(); log.info("[NotificationInbound] onMessage!"); } catch (Exception e) { log.error("[NotificationInbound] ERROR[" + e.getMessage() + "]!!!****"); throw new IllegalStateException(); } }
set CLUSTER_PROPS=-Ddata.dir=../data-server2 -Djnp.port=2099 -Djnp.rmiPort=2098 -Dhornetq.remoting.netty.port=6445 run ../config/stand-alone/clustered
start-cluster1.bat
set CLUSTER_PROPS=-Ddata.dir=../data-server3 -Djnp.port=3099 -Djnp.rmiPort=3098 -Dhornetq.remoting.netty.port=7445 run ../config/stand-alone/clustered
IP=`/sbin/ip a |grep 'inet '|awk -F'/' '{print $1}'|awk '{print $2}'|grep -v 127.0.0.1|head -1` export CLUSTER_PROPS="-Dhornetq.remoting.netty.host=$IP -Djnp.host=$IP" echo $CLUSTER_PROPS sh run.sh ../config/stand-alone/clustered
sh stop.sh ../config/stand-alone/clustered
<discovery-groups> <discovery-group name="my-discovery-group"> <local-bind-address>172.16.9.7</local-bind-address> <group-address>231.7.7.7</group-address> <group-port>9876</group-port> <refresh-timeout>10000</refresh-timeout> </discovery-group> </discovery-groups> <connection-factory name="ConnectionFactory"> <discovery-group-ref discovery-group-name="my-discovery-group"/> <entries> <entry name="/ConnectionFactory"/> </entries> </connection-factory>
final String groupAddress = "231.7.7.7"; final int groupPort = 9876; ConnectionFactory jmsConnectionFactory = HornetQJMSClient.createConnectionFactory(groupAddress, groupPort); Connection jmsConnection1 = jmsConnectionFactory.createConnection(); Connection jmsConnection2 = jmsConnectionFactory.createConnection();
<cluster-connections> <cluster-connection name="my-cluster"> <address>jms</address> <retry-interval>500</retry-interval> <use-duplicate-detection>true</use-duplicate-detection> <forward-when-no-consumers>false</forward-when-no-consumers> <max-hops>1</max-hops> <discovery-group-ref discovery-group-name="my-discovery-group"/> </cluster-connection> </cluster-connections>
<connection-factory name="ConnectionFactory"> <discovery-group-ref discovery-group-name="my-discovery-group"/> <entries> <entry name="/ConnectionFactory"/> </entries> <ha>true</ha> <connection-load-balancing-policy-class-name> org.hornetq.api.core.client.loadbalance.RandomConnectionLoadBalancingPolicy </connection-load-balancing-policy-class-name> </connection-factory>
<?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:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:jms="http://www.springframework.org/schema/jms" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean id="messageTopic" class="org.hornetq.api.jms.HornetQJMSClient" factory-method="createTopic"> <constructor-arg value="topic1" /> </bean> <bean id="searchAddMessageQueue" class="org.hornetq.api.jms.HornetQJMSClient" factory-method="createQueue"> <constructor-arg value="ExpiryQueue"></constructor-arg> </bean> <!-- <bean id="transportConfiguration" class="org.hornetq.api.core.TransportConfiguration"> <constructor-arg value="org.hornetq.core.remoting.impl.netty.NettyConnectorFactory" /> <constructor-arg> <map key-type="java.lang.String" value-type="java.lang.Object"> <entry key="host" value="localhost"></entry> <entry key="port" value="5445"></entry> </map> </constructor-arg> </bean> --> <bean id="transportConfiguration" class="org.hornetq.api.core.DiscoveryGroupConfiguration"> <constructor-arg name="groupAddress" value="231.7.7.7" /> <constructor-arg name="groupPort" value="9876"> </constructor-arg> </bean> <bean id="connectionFactory" class="org.hornetq.api.jms.HornetQJMSClient" factory-method="createConnectionFactoryWithHA" destroy-method="close"> <constructor-arg type="org.hornetq.api.jms.JMSFactoryType" value="CF" /> <constructor-arg ref="transportConfiguration" /> </bean> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="connectionFactory" /> <property name="pubSubDomain" value="true" /> </bean> <bean id="topicService" class="org.langke.hornetq.ClientServiceImpl"> <property name="jmsTemplate" ref="jmsTemplate" /> <property name="topic" ref="messageTopic" /> </bean> <bean id="sendMessageService" class="org.langke.hornetq.SendMessageServiceImpl"> <property name="jmsTemplate" ref="jmsTemplate"></property> <property name="searchAddMessageQueue" ref="searchAddMessageQueue"></property> </bean> <!-- this is the Message Driven POJO (MDP) <bean id="messageListener" class="org.langke.hornetq.MessageListenerImpl"> </bean> --> <bean id="receiveMessageListener" class="org.langke.hornetq.ReceiveMessageListenerImpl"></bean> <!-- and this is the message listener container --> <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory" /> <!-- <property name="destination" ref="messageTopic" /> --> <property name="destination" ref="searchAddMessageQueue"></property> <property name="messageListener" ref="receiveMessageListener" /> </bean> </beans>
package org.langke.common.hornetq; public interface MessageService { public boolean sendMessage(SerializableObject message) ; }
3.2发送消息
package org.langke.common.hornetq; import java.io.Serializable; public class SerializableObject implements Serializable{ /** * */ private static final long serialVersionUID = 1L; private Object obj ; private Boolean isRetry = true; public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } public Boolean getIsRetry() { return isRetry; } public void setIsRetry(Boolean isRetry) { this.isRetry = isRetry; } }
package org.langke.common.hornetq; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.ObjectMessage; import javax.jms.Queue; import javax.jms.Session; import org.apache.log4j.Logger; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.MessageCreator; public class SendMessageServiceImpl implements MessageService { private static final Logger logger = Logger.getLogger(SendMessageServiceImpl.class); private JmsTemplate jmsTemplate; private Queue searchAddMessageQueue; @Override public boolean sendMessage(SerializableObject message) { return sendQueue(message); } private boolean sendQueue(final SerializableObject so) { try { logger.info("start to send queue to " + searchAddMessageQueue.getQueueName() + ", message : " + so); jmsTemplate.send(searchAddMessageQueue, new MessageCreator() { @Override public Message createMessage(Session session) throws JMSException { ObjectMessage om = session.createObjectMessage(so); return om; } }); return true; } catch (Exception e) { logger.error("Error: send topic failure:" + e.getMessage(), e); return false; } } public JmsTemplate getJmsTemplate() { return jmsTemplate; } public void setJmsTemplate(JmsTemplate jmsTemplate) { this.jmsTemplate = jmsTemplate; } public Queue getSearchAddMessageQueue() { return searchAddMessageQueue; } public void setSearchAddMessageQueue(Queue searchAddMessageQueue) { this.searchAddMessageQueue = searchAddMessageQueue; } }
3.3接收消息
package org.langke.common.hornetq; import java.util.concurrent.atomic.AtomicInteger; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.ObjectMessage; import org.apache.log4j.Logger; public class ReceiveMessageListenerImpl implements MessageListener { private AtomicInteger count = new AtomicInteger(0); private static Logger logger = Logger.getLogger(ReceiveMessageListenerImpl.class); @Override public void onMessage(Message message) { try{ if(message instanceof ObjectMessage){ ObjectMessage objectMessage = (ObjectMessage)message; if(objectMessage.getObject() instanceof SerializableObject){ SerializableObject so = (SerializableObject) objectMessage.getObject(); logger.info(so.getObj()); }else{ logger.info(objectMessage); } }else{ System.out.println(message); } } catch (JMSException e) { logger.error( "Error: receive message from topic failure: " + e.getMessage(), e); }finally{ System.out.println(count.incrementAndGet()); } } }
3.4调用示例
package org.langke.common.hornetq; import java.io.File; import java.util.HashMap; import java.util.Map; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class Test { private static ApplicationContext ctx; private static Test instance=new Test(); public static Test getInstance(){ return instance; } private Test() { if(ctx == null) { String location = null; if(System.getProperty("os.name").toLowerCase().contains("windows")){ location = "conf/applicationContext.xml"; }else{ location = "../conf/applicationContext.xml"; } File file = new File(location); ctx = new FileSystemXmlApplicationContext(location); } } /** * @param args */ public static void main(String[] args) { getInstance(); MessageService service = ctx.getBean("sendMessageService", MessageService.class); for(int i=0;i<3000;i++){ Map map = new HashMap(); map.put("ooxx", i); SerializableObject so = new SerializableObject(); so.setObj(map); service.sendMessage(so); } } }