Activemq+spring整合

6 篇文章 1 订阅

activemq与spring的整合需要用到线程池。考虑到连接、会话等资源的建立和释放,无须人工操作,全部交给容器来处理。这里通过一个实例讲解activemq与spring如何整合。项目大致是这样的设计:通过jetty构建一个http请求,接收http://localhost:8080/send?msg=xxx的请求,然后将msg作为消息传递给生产者线程,将消息发送到指定的Queue,这里发送消息基本完成,为了验证接收消息,这里配置一个消费者,用来监听实时消息,而不是通过循环来读取消息,因此需要注册一个消息监听器,来监听生产者发送的消息,然后将接收的消息打印出来,完成activemq与spring整合之后发送接收的测试。

1、构建maven项目,并引入依赖库。项目最终项目结构如下:

pom.xml文件如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.xxx.activemq</groupId>
  <artifactId>sendmessage</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>sendmessage</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring-version>4.3.4.RELEASE</spring-version>
  </properties>

  <dependencies>
       <dependency>
              <groupId>org.eclipse.jetty</groupId>
              <artifactId>test-jetty-servlet</artifactId>
              <version>8.1.0.RC5</version>
        </dependency>
       <dependency>
   		      <groupId>log4j</groupId>
   		      <artifactId>log4j</artifactId>
   		      <version>1.2.17</version>
   		</dependency>
   		<dependency>
   		      <groupId>org.slf4j</groupId>
   		      <artifactId>slf4j-log4j12</artifactId>
   		      <version>1.7.21</version>
   		</dependency>
       <dependency>
   		      <groupId>commons-lang</groupId>
   		      <artifactId>commons-lang</artifactId>
   		      <version>2.6</version>
    	</dependency>
    	<dependency>
	        <groupId>org.apache.commons</groupId>
	        <artifactId>commons-pool2</artifactId>
	        <version>2.4.2</version>
	    </dependency>
       <dependency>
              <groupId>org.apache.activemq</groupId>
              <artifactId>activemq-all</artifactId>
              <version>5.15.0</version>
       </dependency>
       <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-beans</artifactId>
              <version>${spring-version}</version>
       </dependency>
       <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-context</artifactId>
              <version>${spring-version}</version>
       </dependency>
       <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-jms</artifactId>
              <version>${spring-version}</version>
       </dependency>
  </dependencies>
</project>

2、主要用到的类介绍

ISendService.java

package com.xxx.activemq.service;

public interface ISendService {
	public void send(String msg);
}

SendService.java,将/send?msg=xxx发送过来的msg参数作为消息发送给activemq的一个Queue,这里是brokerQueue,后面的applicationContext.xml配置文件中会配置该Queue。

package com.xxx.activemq.service;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;
import org.apache.log4j.Logger;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
public class SendService implements ISendService{
	
	private static final Logger LOG = Logger.getLogger(SendService.class);
	private String queueName;
	private JmsTemplate jmsTemplate;
	private ThreadPoolTaskExecutor threadExecutor;

	@Override
	public void send(String msg) {
		threadExecutor.execute(new Runnable() {			
			@Override
			public void run() {
				jmsTemplate.send(queueName,new MessageCreator() {					
					@Override
					public Message createMessage(Session session) throws JMSException {
						return session.createTextMessage(msg);
					}
				});
				LOG.info(String.format("send msg %s to "+queueName+" ok.", msg));
			}
		});
	}

	public String getQueueName() {
		return queueName;
	}

	public void setQueueName(String queueName) {
		this.queueName = queueName;
	}

	public JmsTemplate getJmsTemplate() {
		return jmsTemplate;
	}

	public void setJmsTemplate(JmsTemplate jmsTemplate) {
		this.jmsTemplate = jmsTemplate;
	}

	public ThreadPoolTaskExecutor getThreadExecutor() {
		return threadExecutor;
	}

	public void setThreadExecutor(ThreadPoolTaskExecutor threadExecutor) {
		this.threadExecutor = threadExecutor;
	}
	
}
SendServlet.java,负责处理/send?msg=xxx请求的Servlet。
package com.xxx.activemq.servlet;
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.xxx.activemq.service.SendService;
import com.xxx.activemq.utils.WebContext;
public class SendServlet extends HttpServlet{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static SendService sendService;
	static{
		sendService = (SendService)WebContext.getBean("sendService");
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		doPost(req, res);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		String message = req.getParameter("msg");
		sendService.send(message);
		res.setCharacterEncoding("UTF-8");
		res.setContentType("application/json");
		res.setStatus(HttpServletResponse.SC_OK);
		res.getWriter().println("{\"message\":\"ok\"}");
	}
}
App.java,程序入口,这里会利用jetty,构建一个http的服务,监听8080端口,然后添加handler,接收来自http://localhost:8080/send?msg=xxx的请求。

package com.xxx.activemq.webapp;
import org.apache.log4j.Logger;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.xxx.activemq.servlet.SendServlet;
import com.xxx.activemq.utils.WebContext;

public class App {

	private static final int PORT = 8080;
	private static final Logger LOG = Logger.getLogger(App.class);
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		WebContext.setContext(context);
		Server server = new Server(PORT);
		ServletContextHandler handler = new ServletContextHandler(ServletContextHandler.SESSIONS);
		handler.setContextPath("/");
		handler.addServlet(new ServletHolder(new SendServlet()), "/send");
		server.setHandler(handler);
		try {
			LOG.info("webapp initialize success!");
			server.start();
			server.join();			
		} catch (Exception e) {
			LOG.error("webapp initialize error!");
		}
	}

}
WebContext.java,工具类,利用spring容器中定义的bean来创建bean实例。

package com.xxx.activemq.utils;

import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class WebContext implements ApplicationContextAware {
	
	private static final Logger LOG = Logger.getLogger(WebContext.class);
	private static ApplicationContext context;

	public void setApplicationContext(ApplicationContext context)
			throws BeansException {
		LOG.info("applicationContext init...");
		setContext(context);
	}

	public static void setContext(ApplicationContext context) {
		WebContext.context = context;		
	}
	
	public static Object getBean(String name){
		if(context==null){
			LOG.error("context is null");
			return null;
		}
		return context.getBean(name);
	}
}
ConsumerMessageListener.java,这个类用来接收消息,接收SendService.java中发送的消息,这个实时接收消息。

package com.xxx.activemq.listener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
import org.apache.log4j.Logger;
public class ConsumerMessageListener implements MessageListener {
	private static Logger LOG = Logger.getLogger(ConsumerMessageListener.class);
	@Override
	public void onMessage(Message msg) {
		if(msg instanceof TextMessage){
			TextMessage o = (TextMessage)msg;
			try {
				LOG.info("received message: " + o.getText());
			} catch (JMSException e) {
				LOG.error("received message for error!");
			}
		}
	}
}

配置文件:

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"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
      
      <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
           <property name="locations">
               <list>
                     <value>classpath:config.properties</value>
               </list>
           </property>
      </bean> 
        
      
      <bean id="jmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory" destroy-method="stop">
             <property name="connectionFactory">
                   <bean class="org.apache.activemq.ActiveMQConnectionFactory">
		            <property name="brokerURL" value="${activemq.brokerURL}"></property>
		            <property name="useAsyncSend" value="true"/>
		            <property name="redeliveryPolicy">
		                 <bean class="org.apache.activemq.RedeliveryPolicy">
		                       <property name="initialRedeliveryDelay" value="2000"/>
		                       <property name="useExponentialBackOff" value="true"/>
		                 </bean>
		            </property>
                 </bean> 
             </property>
      </bean>
       
      <bean id="connectionFactory" class="org.springframework.jms.connection.SingleConnectionFactory">
			 <property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
	  </bean> 
      <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
             <property name="connectionFactory" ref="connectionFactory"/>
      </bean>
      <bean id="threadExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
            <property name="corePoolSize" value="${sendmsgspool.poolsize}" />
		    <property name="keepAliveSeconds" value="${sendmsgspool.keepaliveseconds}" />
		    <property name="maxPoolSize" value="${sendmsgspool.maxpoolsize}" />
		    <property name="rejectedExecutionHandler">  
			<bean class="java.util.concurrent.ThreadPoolExecutor$DiscardOldestPolicy" />  
			</property>
      </bean>
      <bean id="sendService" class="com.xxx.activemq.service.SendService">
           <property name="queueName" value="brokerQueue" />
           <property name="jmsTemplate" ref="jmsTemplate"/>
           <property name="threadExecutor" ref="threadExecutor"/>
      </bean> 
      <!-- 发送消息以上这些配置足够了 -->
      <!-- 下面配置收消息的消费者 -->     
      <bean id="consumerMessageListener" class="com.xxx.activemq.listener.ConsumerMessageListener">     
      </bean>
      <bean id="brokerQueue" class="org.apache.activemq.command.ActiveMQQueue">
            <constructor-arg value="${activemq.brokerQueue}"/>
      </bean>
      <bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
            <property name="connectionFactory" ref="connectionFactory"/>
            <property name="messageListener" ref="consumerMessageListener"/>
            <property name="destination" ref="brokerQueue"/>
      </bean>
</beans>
config.properties ,指定brokerURL及队列名发送消息线程池信息。

activemq.brokerURL=tcp://localhost:61616
activemq.brokerQueue=brokerQueue
sendmsgspool.keepaliveseconds=300
sendmsgspool.maxpoolsize=50
sendmsgspool.poolsize=15
log4j.xml(略)

3、启动App.java,监听8080端口,接收http://localhost:8080/send?msg=xxx的请求,然后将参数msg作为消息利用生产者发送给消息接收者。

项目启动成功日志:

第一次请求:

控制台日志:

第二次请求:

控制台日志:

管理界面查看队列消息:

4、这里重要的就是要理清jmsTemplate,jmsContainer,connectionFactory,jmsConnectionFactory之间的关系。

activemq与spring的整合和java直接编写activemq实例最大的区别在于,connection,session等资源的创建和释放无需人为操作,看不到很直观的API调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luffy5459

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值