如何用Spring整和ActiveMQ?

来源:互联网 发布:协方差矩阵计算公式 编辑:程序博客网 时间:2024/05/17 03:53

问题一:为什么要整合ActiveMQ?

  传统的JDBC代码在处理连接、语句、结果集和异常时是多么冗长和繁杂你一定不会忘记,传统的JMS继承了JDBC的“关荣传统”。发送一个简单的消息,要几行代码呢?请仔细数数吧。

  Java代码

以下是引用片段:
public void sendMessage() throws JMSException {    
    ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(    
    "tcp://localhost:61616");    
    Connection connection = null;    
    Session session=null;    
    try {    
            
        connection = (Connection) connectionFactory.createConnection();//创建连接    
        session = (Session) connection.createSession(false,    
                Session.AUTO_ACKNOWLEDGE);//创建会话    
        Destination destination = session.createQueue("myQueue");    
        MessageProducer producer = session.createProducer(destination);    
        TextMessage message = session.createTextMessage(expectedBody);    
        message.setStringProperty("headname", "remoteB");    
        producer.send(message);    
        connection.close();    
    } catch (Exception e) {    
        e.printStackTrace();    
    }finally{    
        try {    
            if(session!=null){    
                session.close();    
            }    
            if(connection!=null){    
                connection=null;    
            }    
        } catch (Exception e) {    
                
        }    
    }    
}   
 public void sendMessage() throws JMSException { 
  ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory( 
  "tcp://localhost:61616"); 
  Connection connection = null; 
  Session session=null; 
  try { 
    
   connection = (Connection) connectionFactory.createConnection();//创建连接 
   session = (Session) connection.createSession(false, 
     Session.AUTO_ACKNOWLEDGE);//创建会话 
   Destination destination = session.createQueue("myQueue"); 
   MessageProducer producer = session.createProducer(destination); 
   TextMessage message = session.createTextMessage(expectedBody); 
   message.setStringProperty("headname", "remoteB"); 
   producer.send(message); 
   connection.close(); 
  } catch (Exception e) { 
   e.printStackTrace(); 
  }finally{ 
   try { 
    if(session!=null){ 
     session.close(); 
    } 
    if(connection!=null){ 
     connection=null; 
    } 
   } catch (Exception e) { 
     
   } 
  } 
 } 

  传统接受消息而是类似的代码,其实我们的目的就是发送和接受消息。幸运的是Spring为我们提供了大量的模板。项目一期用的较多的是JdbCTemplate,spring也为我们提供了JMSTemplate模板。

  问题二:JMSTemplate模板该如何配置呢?

  类似于jdbcTemplate,首先要配置一个ConnectionFactory,我们采用ActiveMQ5.2作为消息服务器。之后要开始配置JmsTemplate模板了。最后是配置消息目标了。消息分为队列和主题两大类,因此要配置两个消息目标了。

  Java代码

以下是引用片段:
<!-- ActiveMQ -->    
        
    <!-- 配置JMS连接工厂 -->      
    <bean id="JmsConnectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">      
        <property name="brokerURL" value="tcp://localhost:61616"/>      
    </bean>      
    <!-- 配置JMS模版 -->      
    <bean id="JmsTemplate" class="org.springframework.jms.core.JmsTemplate">      
        <property name="connectionFactory" ref="JmsConnectionFactory"/>      
    </bean>      
    <!-- 发送消息的目的地(队列) -->      
    <bean id="QueueDestination" class="org.apache.activemq.command.ActiveMQQueue">      
        <!-- 设置消息队列的名字 -->      
        <constructor-arg index="0" value="HelloWorldQueue"/>      
    </bean>    
    <!-- 发送消息的目的地(主题) -->      
    <bean id="TopicDestination" class="org.apache.activemq.command.ActiveMQTopic">      
        <!-- 设置消息主题的名字 -->      
        <constructor-arg index="0" value="FlexTopic"/>      
    </bean>      
<!-- ActiveMQ --> 
     
    <!-- 配置JMS连接工厂 -->   
    <bean id="JmsConnectionFactory" class="org.apache.activemq.spring.ActiveMQConnectionFactory">   
     <property name="brokerURL" value="tcp://localhost:61616"/>   
    </bean>   
    <!-- 配置JMS模版 -->   
    <bean id="JmsTemplate" class="org.springframework.jms.core.JmsTemplate">   
     <property name="connectionFactory" ref="JmsConnectionFactory"/>   
    </bean>   
    <!-- 发送消息的目的地(队列) -->   
    <bean id="QueueDestination" class="org.apache.activemq.command.ActiveMQQueue">   
     <!-- 设置消息队列的名字 -->   
     <constructor-arg index="0" value="HelloWorldQueue"/>   
    </bean> 
    <!-- 发送消息的目的地(主题) -->   
    <bean id="TopicDestination" class="org.apache.activemq.command.ActiveMQTopic">   
     <!-- 设置消息主题的名字 -->   
     <constructor-arg index="0" value="FlexTopic"/>   
    </bean>    

  问题三:如何使用JmsTemplate发送消息呢?

  spring的beanfactory得到一个jmsTemplate的实例和消息目标的实例,发送消息,够简单的吧。看看代码:

  Java代码

以下是引用片段:
JmsTemplate template = (JmsTemplate) SpringContext.getBean("JmsTemplate");    
            ActiveMQTopic destination=(ActiveMQTopic)SpringContext.getBean("TopicDestination");    
            template.send((javax.jms.Destination) destination, new MessageCreator(){    
                public Message createMessage(Session session) throws JMSException {    
                    return session.createTextMessage("hello");    
                }    
                    
            });   
JmsTemplate template = (JmsTemplate) SpringContext.getBean("JmsTemplate"); 
   ActiveMQTopic destination=(ActiveMQTopic)SpringContext.getBean("TopicDestination"); 
   template.send((javax.jms.Destination) destination, new MessageCreator(){ 
    public Message createMessage(Session session) throws JMSException { 
     return session.createTextMessage("hello"); 
    } 
     
   }); 

  问题四:上面的代码能不能在简单些?

  很多时候,发送消息的目标都是默认的,因此是不是可以在jmsTemplate中设置一个默认的消息目标呢?答案是肯定的。

  Java代码

以下是引用片段:
<!-- 配置JMS模版 -->      
   <bean id="JmsTemplate" class="org.springframework.jms.core.JmsTemplate">      
    <property name="connectionFactory" ref="JmsConnectionFactory"/>    
    <property name="defaultDestination" ref="TopicDestination"></property>    
   </bean>    
 <!-- 配置JMS模版 -->   
    <bean id="JmsTemplate" class="org.springframework.jms.core.JmsTemplate">   
     <property name="connectionFactory" ref="JmsConnectionFactory"/> 
     <property name="defaultDestination" ref="TopicDestination"></property> 
    </bean>  

  发送消息的时候,不指定目标,spring就会调用默认的目标了。

  Java代码

以下是引用片段:
JmsTemplate template = (JmsTemplate) SpringContext.getBean("JmsTemplate");    
            template.send( new MessageCreator(){    
                public Message createMessage(Session session) throws JMSException {    
                    return session.createTextMessage("hello");    
                }    
            });   
JmsTemplate template = (JmsTemplate) SpringContext.getBean("JmsTemplate"); 
   template.send( new MessageCreator(){ 
    public Message createMessage(Session session) throws JMSException { 
     return session.createTextMessage("hello"); 
    } 
   }); 

  问题四:jmsTemplate怎么接受信息?

  jmsTemplate接收消息十分的简单,只需要调用template.receive()方法,receive方法是同步的,默认情况下,对receive()方法的调用会造成阻塞,知道消息到达目标----如果必要,永远等下去。为了避免对消息内容等待,可以配置jmsTemplate时,通过设置receiveTimeout属性来指定接收消息超时时间。下面的配置将接收消息的超时时间设置为一分钟(60000毫秒)。

  Xml代码

以下是引用片段:
<!-- 配置JMS模版 -->      
   <bean id="JmsTemplate" class="org.springframework.jms.core.JmsTemplate">      
    <property name="connectionFactory" ref="JmsConnectionFactory"/>   
    <property name="defaultDestination" ref="TopicDestination"></property>   
    <property name="receiveTimeout" value="60000"></property>   
   </bean>     
 <!-- 配置JMS模版 -->   
    <bean id="JmsTemplate" class="org.springframework.jms.core.JmsTemplate">   
     <property name="connectionFactory" ref="JmsConnectionFactory"/> 
     <property name="defaultDestination" ref="TopicDestination"></property> 
     <property name="receiveTimeout" value="60000"></property> 
    </bean>   

  template.receive()会从默认目标接收消息,如果你希望指定一个目标,可以传一个目标。如:template.receive("myQueue").

  同步接收消息并不是spring唯一的选择,消息监听器可以实现异步(下篇文章将会介绍消息驱动)。

  问题五:怎么自动将消息转化为Java对象?

  转化器在很多组件中都是必不缺少的东西。Spring挺过MessageConverter接口提供了对消息转换的支持。

  Java代码

以下是引用片段:
public class MyMessageConverter implements MessageConverter {    
    @Override   
    public Object fromMessage(Message arg0) throws JMSException,    
            MessageConversionException {    
        // TODO Auto-generated method stub    
        return null;    
    }    
    @Override   
    public Message toMessage(Object arg0, Session arg1) throws JMSException,    
            MessageConversionException {    
        // TODO Auto-generated method stub    
        return null;    
    }    
}   
public class MyMessageConverter implements MessageConverter { 
 @Override 
 public Object fromMessage(Message arg0) throws JMSException, 
   MessageConversionException { 
  // TODO Auto-generated method stub 
  return null; 
 } 
 @Override 
 public Message toMessage(Object arg0, Session arg1) throws JMSException, 
   MessageConversionException { 
  // TODO Auto-generated method stub 
  return null; 
 } 
}

  MessageConverter接口的两个方法简单明了。在发送端toMessage会将java对象转化为消息,在接收端fromMessage会将消息转化为java对象。

  下面的代码简单的实现了MessageConverter的两个接口。

以下是引用片段:
  Java代码  
public class MyMessageConverter implements MessageConverter {    
    @Override   
    public Object fromMessage(Message message) throws JMSException,    
            MessageConversionException {    
        if(!(message instanceof MapMessage)){    
            throw new MessageConversionException("Messae is not MapMessage");    
        }    
        MapMessage mapMessage=(MapMessage)message;    
        MessageObj messageObj=new MessageObj();    
        messageObj.setId(mapMessage.getString("id"));    
        messageObj.setInfo(mapMessage.getString("info"));    
        return messageObj;    
    }    
    @Override   
    public Message toMessage(Object obj, Session session) throws JMSException,    
            MessageConversionException {    
        if(!(obj instanceof MessageObj)){    
            throw new MessageConversionException("obj is not MessageObj");    
        }    
        MessageObj messageObj=(MessageObj)obj;    
        MapMessage mapMessage=session.createMapMessage();    
        mapMessage.setString("id", messageObj.getId());    
        mapMessage.setString("info", messageObj.getInfo());    
        return mapMessage;    
    }    
}   
public class MyMessageConverter implements MessageConverter { 
 @Override 
 public Object fromMessage(Message message) throws JMSException, 
   MessageConversionException { 
  if(!(message instanceof MapMessage)){ 
   throw new MessageConversionException("Messae is not MapMessage"); 
  } 
  MapMessage mapMessage=(MapMessage)message; 
  MessageObj messageObj=new MessageObj(); 
  messageObj.setId(mapMessage.getString("id")); 
  messageObj.setInfo(mapMessage.getString("info")); 
  return messageObj; 
 } 
 @Override 
 public Message toMessage(Object obj, Session session) throws JMSException, 
   MessageConversionException { 
  if(!(obj instanceof MessageObj)){ 
   throw new MessageConversionException("obj is not MessageObj"); 
  } 
  MessageObj messageObj=(MessageObj)obj; 
  MapMessage mapMessage=session.createMapMessage(); 
  mapMessage.setString("id", messageObj.getId()); 
  mapMessage.setString("info", messageObj.getInfo()); 
  return mapMessage; 
 } 

  此时,发送和接收消息要换成template.convertAndSend(message);template.receiveAndConvert();

  可是jmsTemplate如何知道消息转换器呢?需要在配置jmsTemplate的时候,加上messageConverter属性。

  Java代码

以下是引用片段:
<!-- 配置JMS模版 -->      
   <bean id="JmsTemplate" class="org.springframework.jms.core.JmsTemplate">      
    <property name="connectionFactory" ref="JmsConnectionFactory"/>    
    <property name="defaultDestination" ref="TopicDestination"></property>    
    <property name="receiveTimeout" value="60000"></property>    
    <property name="messageConverter" ref="messageObj"></property>    
   </bean>     
 <!-- 配置JMS模版 -->   
    <bean id="JmsTemplate" class="org.springframework.jms.core.JmsTemplate">   
     <property name="connectionFactory" ref="JmsConnectionFactory"/> 
     <property name="defaultDestination" ref="TopicDestination"></property> 
     <property name="receiveTimeout" value="60000"></property> 
     <property name="messageConverter" ref="messageObj"></property> 
    </bean>   

  messageObj是要转化的java对象的bean的id。

原创粉丝点击