从Spring容器初始化到ActiveMq配置线程池的源代码解读

本文从Spring容器初始化的角度出发,深入探讨ActiveMq配置线程池的源代码实现。通过分析web.xml中的配置,讲解了ServletContextListener如何监听Web应用生命周期,并详细解析了DefaultMessageListenerContainer和ThreadPoolTaskExecutor的初始化过程。线程池的使用旨在降低资源消耗、提高响应速度和加强线程管理,文中还介绍了线程池的工作原理和核心方法。
摘要由CSDN通过智能技术生成

由于项目前期的消息机制是用redis自带的消息机制架构的,redis自带的消息机制不够专业,容易丢数据,因此项目组决定换掉redis消息机制,采用比较专业的ActiveMq,

因此需要对ActiveMq的性能和稳定性作下测试,在测试过程中自己很佩服别人的代码设计,只通过几段配置就能让系统正常用转,只通过改个数字就能让系统的吞吐量成倍提升。下面代码是我写的一个demo的配置代码

	<!-- 用户注册 消息消费者-->
	<bean id="userRegisterConsumer" class="com.ydm.consumer.web.UserConsumer" >
	</bean>
	<!-- 线程池 -->
	<bean id="userRegisterMessageExecutor"
		class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
		<property name="corePoolSize" value="20" />
		<property name="maxPoolSize" value="100" />
		<property name="daemon" value="true" />
		<property name="keepAliveSeconds" value="120" />
	</bean>
	<!-- 目标监听队列 -->
	<bean id="userRegisterDestination" class="org.apache.activemq.command.ActiveMQQueue">
		<constructor-arg index="0" value="ydm-queue" />
	</bean>
	
	<!-- 监听器 -->
	<bean id="userRegisterListenerContainer"
		class="org.springframework.jms.listener.DefaultMessageListenerContainer">
		<property name="connectionFactory" ref="jmsFactory" />
		<property name="receiveTimeout" value="1000" />
		<property name="destination" ref="userRegisterDestination" />
		<property name="messageListener" ref="userRegisterConsumer" />
		<property name="taskExecutor" ref="userRegisterMessageExecutor"></property>
		<property name="concurrentConsumers" value="5"></property>
	</bean>
上面注释也已经表明了,配置了一个UserConsumer,代码如下

public class UserConsumer implements MessageListener {

	Logger logger=Logger.getLogger(UserConsumer.class);

	@Override
	public void onMessage(Message message) {
		try {
			ObjectMessage objectMessage=(ObjectMessage)message;
			UserModel userModel=(UserModel)objectMessage.getObject();
			logger.error(Thread.currentThread().getName()+"消费了"+userModel);
		} catch (JMSException e) {
			e.printStackTrace();
		}
	}
}
配置了一个线程池,一个目标队列,一个监听器,通过上述配置项目就可以正常运转,而且消费者还是以多线程的形式在消费,这样我们可以适当提供消费者的数量就可以提高处理速度,为什么我仅仅配置上述代码,就可以完成这么复杂的功能,是谁在什么时候调用了onMessage方法?框架到底为我们做了什么?就是带着这种疑问,让我们一起来了解一下幕后吧。

 首先我们要了解spring IOC容器是如何初始化的

  一般我们初始化spring 容器会在web.xml中增加下面一段配置,那让我们来看看它的实现吧

 

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>


public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

	private ContextLoader contextLoader;

	public ContextLoaderListener() {
	}
	public ContextLoaderListener(WebApplicationContext context) {
		 super(context);
	}

	/**
	 * Initialize the root web application context.
	  */
	 public void contextInitialized(ServletContextEvent event) {
		this.contextLoader = createContextLoader();
		 if (this.contextLoader == null) {
			 this.contextLoader = this;
		 }
		this.contextLoader.initWebApplicationContext(event.getServletContext());
	}

	/**
	 * Close the root web application context.
	 */
	public void contextDestroyed(ServletContextEvent event) {
		if (this.contextLoader != null) {
			this.contextLoader.closeWebApplicationContext(event.getServletContext());
		}
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}

}
这个类继承了ContextLoader,实现了ServletContextListener接口
ContextLoader我们主要看它的静态初始化块


	static {
		// Load default strategy implementations from properties file.
		// This is currently strictly internal and not meant to be customized
		// by application developers.
		try {
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
		}
	}
这里主要加载了ContextLoader.properties配置文件,返回一个 Properties对象,配置文件里就一行代码

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

我们来看ServletContextListener接口,这个接口我相信大家应该都不陌生,它属于servlet api 里的内容,它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期。当Servlet 容器启动或终止Web 应用时,会触发ServletContextEvent 事件,该事件由ServletContextListener 来处理。在 ServletContextListener 接口中定义了处理ServletContextEvent 事件的两个方法

public interface ServletContextListener extends EventListener {
	/**
	 ** Notification that the web application initialization
	 ** process is starting.
	 ** All ServletContextListeners are notified of context
	 ** initialization before any filter or servlet in the web
	 ** application is initialized.
	 */

    public void contextInitialized ( ServletContextEvent sce );

	/**
	 ** Notification that the servlet context is about to be shut down.
	 ** All servlets and filters have been destroy()ed before any
	 ** ServletContextListeners are notified of context
	 ** destruction.
	 */
    public void contextDestroyed ( ServletContextEvent sce );
}

源代码注释上已经写的很明白了,这里就不在熬述ContextLoaderListener重写了contextInitialized方法,上面已经贴出代码了,这里有这样一句话

		if (this.contextLoader == null) {
			this.contextLoader = this;
		}
这个this是指的什么?这个就要扯远了,这个应该跟容器有关,我用的是tomcat,它指的是Tomcat 的StandardContext,这个我也没有继续深究,怕走远了回不来了,有兴趣的可以查看tomcat的源码。

接下来让我们看看initWebApplicationContext的实现

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

		Log logger = LogFactory.getLog(ContextLoader.class);
		servletContext.log("Initializing Spring root WebApplicationContext");
		if (logger.isInfoEnabled()) {
			logger.info("Root WebApplicationContext: initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// Store context in local instance variable, to guarantee that
			// it is available on ServletContext shutdown.
			if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, ser
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值