Spring整合ActiveMQ之嵌入(二)

    首先说明,本文不是坑,本文所需源码和项目我会存到我的云盘里,欢迎大家下载和学习。

    JMS作为一个可以实现订阅式和队列式的推送消息中间件,一直待web项目中占有一席之地。在普通的Spring整合JMS中,ActiveMQ都是作为一个单独的线程独立启动的,也就意味着,在部署自己开发的项目时,就必须依赖ActiveMQ这个中间件的优先启动。也就是说,如果没有事先启动ActiveMQ这个中间件,自己的项目也就无法正常启动和使用。

    由于很多项目并不希望在本项目之外另外跑一个线程,因此本文就将着重讲解如何将支持JMS消息订阅的ActiveMQ整体嵌入到web项目中,当本文结束,就会实现仅仅启动自己开发的项目就可以成功的发送和接受消息。

    这个测试案例将使用Spring+JMS+tomcat/weblogic开发,开发工具为myeclipse 10,jdk版本为 6.40.

1.jar包

    首先得说一下将ActiveMQ嵌入Spring中所需要的jar包。

    

181213_X8Nj_2303434.png

这是基本的jar包,必须有,否则项目不能跑起来,

 2 .配置文件

        首先配置web.xml文件

 <?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 <display-name></display-name>
 <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
 </welcome-file-list>
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:applicationContext.xml</param-value>
 </context-param>
 <!-- 检查模型 -->
 <servlet>
  <servlet-name>ClassCheckServlet</servlet-name>
  <servlet-class>com.activemq.action.TestJmsService</servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>ClassCheckServlet</servlet-name>
  <url-pattern>login.do</url-pattern>
 </servlet-mapping>
</web-app>

web.xml文件servlet跳转和初始化配置,由于我开发的项目是servlet的项目,因此在这里我采用了,如果想实现Spring管理页面跳转,需要在web.xml文件中添加前端控制器代码,本文不做描述,默认大家可以实现,如果不会实现,请移步到我的博客中查找Spring项目搭建相关文章。

    按照ActiveMQ官方教程,将MQ嵌入Spring项目其实有好几种实现方式,本文就将使用Spring文件配置形式,达到将MQ嵌入的目的。配置applicationContext.xml文件,此文件我放置在src下:

 <?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-5.1.0.xsd
  http://activemq.apache.org/camel/schema/spring 
  http://activemq.apache.org/camel/schema/spring/camel-spring.xsd">
 <!-- 配置嵌入式的 activeMQ Broker -->
 <amq:broker useJmx="false" persistent="true">
  <amq:persistenceAdapter>
   <amq:amqPersistenceAdapter directory="activemq-data"
    maxFileLength="32mb" />
  </amq:persistenceAdapter>
  <amq:transportConnectors>
   <amq:transportConnector uri="tcp://localhost:61616" />
  </amq:transportConnectors>
 </amq:broker>
 <!-- 配置connectionFactory -->
 <bean id="jmsFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
  destroy-method="stop">
  <property name="connectionFactory">
   <bean class="org.apache.activemq.ActiveMQConnectionFactory">
    <property name="brokerURL">
     <value>tcp://localhost:61616</value>
    </property>
   </bean>
  </property>
 </bean>
 <!-- Spring JMS Template -->
 <bean id="myJmsTemplate" class="org.springframework.jms.core.JmsTemplate">
  <property name="connectionFactory">
   <ref local="jmsFactory" />
  </property>
 </bean>
 <!-- 队列 -->
 <!-- <amq:queue id="mytestQueue" physicalName="mytest.embedded" />
 <amq:queue id="retryMyTestQueue" physicalName="retry.mytest.embedded" /> -->
 <!-- 消息订阅模式,在spring xml 里面加,这是发送的 Destination -->
 <bean id="topicDestination" class="org.apache.activemq.command.ActiveMQTopic">
  <!-- 订阅消息的名字 -->
  <constructor-arg index="0" value="orderTopic" />
 </bean>
 <!-- 生产者 -->
 <bean id="mytestProducer" class="com.activemq.jms.MyTestProducer">
  <property name="jmsTemplate">
   <ref bean="myJmsTemplate" />
  </property>
  <property name="destination" ref="topicDestination" />
  <!-- <property name="retryDestination" ref="retryMyTestQueue" /> -->
 </bean>
 <!-- 消费者 -->
 <!-- <bean id="mytestConsumer" class="com.activemq.jms.MyTestConsumer">
  <property name="producer" ref="mytestProducer"></property>
 </bean> -->
 <!-- Spring 监听器 -->
 <bean id="messageListener" class="com.activemq.jms.MyTestConsumer" />
 <bean id="listenerContainer"
  class="org.springframework.jms.listener.SimpleMessageListenerContainer">
  <!-- 工厂 目的地 监听器 这里如果用原始activemq 写,这些属性也是必要的 -->
  <property name="connectionFactory">
   <ref local="jmsFactory" />
  </property>
  <property name="destination" ref="topicDestination" />
  <property name="messageListener" ref="messageListener" />
 </bean>
</beans>

applicationContext.xml文件中的配置有详细的解释,在上面的配置文件中,采用订阅(pub/sub)发布消息模式进行了配置,如果想使用点对点(PTP)形式进行配置,,请将topic相关部分注释掉,并将原先注释掉的代码去掉注释即可。

 

    其实到了这里,已经成功将ActiveMQ嵌入到了项目中,是不是感觉很惊讶?怎么这么简单就嵌入成功了?不信是吧,来,接下来上代码测试。

    由于我开发的项目是servlet的项目,因此在这里我采用了使用工具类获取bean,而不是使用Spring注解的形式获取ben ,原理一样,如果想要使用注解方式获取bena的朋友可以在下面联系我。

    下面是获取ben的工具类,也是一个发送消息的一个中间载体:

 package com.activemq.init;
import java.io.Serializable;
import javax.servlet.ServletContext;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.activemq.jms.MyTestProducer;
public class BeansUtil {
 /**
  * 生产者
  */
 private static MyTestProducer myTestProducer;
 /**
  * 上下文
  */
 private static ApplicationContext context;
 /**
  * 发送Object对象
  * 
  * @param sc
  * @param object
  */
 public static void sendObject(ServletContext sc, Serializable object) {
  getMyTestProducer(sc);
  myTestProducer.sendObjectMsg(object);
 }
 /**
  * 获取myTestProducer
  * 
  * @param sc
  */
 private static void getMyTestProducer(ServletContext sc) {
  context = WebApplicationContextUtils.getWebApplicationContext(sc);
  myTestProducer = (MyTestProducer) context.getBean("mytestProducer");
 }
}

    上面的这个类是一个发送消息的中间载体,起着

 下面是一个真正执行发送任务的类,这个类将会把消息以订阅的形式发送到消息中间件中:

 package com.activemq.jms;
import java.io.Serializable;
import java.util.Map;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.MessagePostProcessor;
/**
 * 
 * @author pengfeiguo
 * 
 *         生产者
 */
public class MyTestProducer {
 private JmsTemplate jmsTemplate;
 private Destination destination;
 private Destination retryDestination;
 public void sendObjectMsg(final Serializable object) {
  jmsTemplate.send(destination, new MessageCreator() {
   public Message createMessage(Session session) throws JMSException {
    return session.createObjectMessage(object);
   }
  });
 }
 /*
  * 发送文本消息
  */
 public void sendTextMsg(Session session, final String msgContent)
   throws JMSException {
  jmsTemplate.send(destination, new MessageCreator() {
   public Message createMessage(Session session) throws JMSException {
    return session.createTextMessage(msgContent);
   }
  });
 }
 /*
  * 发送MAP类型消息
  */
 public void sendMap(Session session, Map<String, Object> map)
   throws JMSException {
  jmsTemplate.convertAndSend(destination, map,
    new MessagePostProcessor() {
     public Message postProcessMessage(Message message)
       throws JMSException {
      // message.setIntProperty("AccountID", 1234);
      // message.setJMSCorrelationID("123-00001");
      return message;
     }
    });
 }
 /**
  * @return the jmsTemplate
  */
 public JmsTemplate getJmsTemplate() {
  return jmsTemplate;
 }
 /**
  * @param jmsTemplate
  *            the jmsTemplate to set
  */
 public void setJmsTemplate(JmsTemplate jmsTemplate) {
  this.jmsTemplate = jmsTemplate;
 }
 /**
  * @return the destination
  */
 public Destination getDestination() {
  return destination;
 }
 /**
  * @param destination
  *            the destination to set
  */
 public void setDestination(Destination destination) {
  this.destination = destination;
 }
 /**
  * @return the retryDestination
  */
 public Destination getRetryDestination() {
  return retryDestination;
 }
 /**
  * @param retryDestination
  *            the retryDestination to set
  */
 public void setRetryDestination(Destination retryDestination) {
  this.retryDestination = retryDestination;
 }
}

 

 下面是一个消息监听类,起着监听发布消息者发布的消息的作用,在这个类中,可以实时监听自己订阅的消息,然后进行下一步处理:

 package com.activemq.jms;
import javax.jms.JMSException;
import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.TextMessage;
import com.activemq.entity.User;
public  class MyTestConsumer implements MessageListener {
 private Message message;
 public void onMessage(Message message) {
  /**
   * 接受文本类型的消息
   */
  if (message instanceof TextMessage) { // instanceof
            // 测试它所指向的对象是否是TextMessage类
   TextMessage text = (TextMessage) message;
   try {
    System.out.println("发送的文本消息内容为:" + text.getText()); // 接受文本消息
   } catch (JMSException e) {
    e.printStackTrace();
   }
  }
  /**
   * 接受Map类型的消息
   */
  if (message instanceof MapMessage) {
   MapMessage map = (MapMessage) message;
   try {
    System.out.println("姓名:" + map.getString("name"));
    System.out.println("是否是英雄:" + map.getBoolean("IsHero"));
    System.out.println("年龄:" + map.getInt("age"));
   } catch (JMSException e) {
    e.printStackTrace();
   }
  }
  if (message instanceof ObjectMessage) {
   ObjectMessage objMsg = (ObjectMessage) message;
   try {
    User person = (User) objMsg.getObject();
    System.out.println("用户名:" + person.getName() + "年龄:"
      + person.getAge() + "地址:" + person.getSex());
   } catch (JMSException e) {
    e.printStackTrace();
   }
  }
  setMessage(message);
 }
 public Message getMessage() {
  return message;
 }
 public void setMessage(Message message) {
  this.message = message;
 }
}

 下面就是一个在web环境中测试的一个action类,此类需要将项目跑起来后,才可以发送消息,

 package com.activemq.action;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.activemq.entity.User;
import com.activemq.init.BeansUtil;
public class TestJmsService extends HttpServlet {
 /**
  * 
  */
 private static final long serialVersionUID = 4811623214895759645L;
 // private MyTestProducer mytestProducer;
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  // TODO Auto-generated method stub
  super.doGet(req, resp);
 }
 @Override
 protected void doPost(HttpServletRequest request, HttpServletResponse resp)
   throws ServletException, IOException {
  String name = request.getParameter("name");
  int age = Integer.parseInt(request.getParameter("age"));
  String sex = request.getParameter("sex");
  User user = new User(name, age, sex);
  BeansUtil.sendObject(this.getServletContext(), user);
 }
}

下面是index页面:

 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
 String path = request.getContextPath();
 String basePath = request.getScheme() + "://"
   + request.getServerName() + ":" + request.getServerPort()
   + path + "/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'index.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
 <form method="post" action="login.do">
  <table>
   <tr>
    <td>姓名:</td>
    <td><input type="text" name="name" />
    </td>
   </tr>
   <tr>
    <td>年龄:</td>
    <td><input type="text" name="age" />
    </td>
   </tr>
   <tr>
    <td>性别:</td>
    <td><input type="text" name="sex" />
    </td>
   </tr>
  </table>
  <input type="submit" value="测试" />
 </form>
</body>
</html>

值得一说的是,这些基本的东西已经能够完全实现将ActiveMQ嵌入到Spring中,而本文使用的User类,只有性命,年龄、性别,三个属性,因此并没有贴出来,使用jms就不需要再启动项目钱首先启动ActiveMQ了,还有不会的朋友可以在下面的链接中下载我所测试的代码;本文完整源码下载,朋友们也可以前往ActiveMQ官网学习如何将ActiveMQ嵌入Spring中,网址为:ActiveMQ官网嵌入教程,下面是另一篇不错的博客文章:ActiveMQ嵌入项目,另:下面是我在淘宝上看到的JMS教学视频,如果朋友们想要细致的学习JMS,可以移步到这里下载JMS视频:JMS教学视频-淘宝,同时欢迎朋友们加入我的QQ群交流:129113306

 

转载于:https://my.oschina.net/guopengfei/blog/535552

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值