Tomcat源码阅读(三)-热加载

热加载

热加载是在不重启Tomcat的情况下,在Context- StandardContext
中重新加载应用的class。热加载是由一个专门的守护线程执行操作的,这个守护线程是ContainerBackgroundProcessor。

在StandardEngine启动时,会调用父类ContainerBase的threadStart()方法,就是在此方法中开启了ContainerBackgroundProcessor 线程!此方法代码如下:

protected void threadStart() {
	if (thread != null)
		return;
	// StandardEngine初始化的构造方法会设置backgroundProcessorDelay的值为10
	if (backgroundProcessorDelay <= 0)
		return;
	threadDone = false;
	String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
	thread = new Thread(new ContainerBackgroundProcessor(), threadName);
	// 守护线程
	thread.setDaemon(true);
	thread.start();
}

ContainerBackgroundProcessor:

protected class ContainerBackgroundProcessor implements Runnable {

	@Override
	public void run() {
		Throwable t = null;
		String unexpectedDeathMessage = sm.getString(
				"containerBase.backgroundProcess.unexpectedThreadDeath",
				Thread.currentThread().getName());
		try {
			while (!threadDone) {
				try {
					// 每10s执行一次
					Thread.sleep(backgroundProcessorDelay * 1000L);
				} catch (InterruptedException e) {
					// Ignore
				}
				if (!threadDone) {
					// 调用processChildren
					processChildren(ContainerBase.this);
				}
			}
		} catch (RuntimeException|Error e) {
			t = e;
			throw e;
		} finally {
			if (!threadDone) {
				log.error(unexpectedDeathMessage, t);
			}
		}
	}
	
	protected void processChildren(Container container) {
		ClassLoader originalClassLoader = null;

		try {
			if (container instanceof Context) {
				Loader loader = ((Context) container).getLoader();
				// Loader will be null for FailedContext instances
				if (loader == null) {
					return;
				}

				// Ensure background processing for Contexts and Wrappers
				// is performed under the web app's class loader
				originalClassLoader = ((Context) container).bind(false, null);
			}
			// StanderContext重写了backgroundProcess(),就是在这个重写方法中进行了热加载
			container.backgroundProcess();
			Container[] children = container.findChildren();
			for (int i = 0; i < children.length; i++) {
				if (children[i].getBackgroundProcessorDelay() <= 0) {
					// 递归调用processChildren
					processChildren(children[i]);
				}
			}
		} catch (Throwable t) {
			ExceptionUtils.handleThrowable(t);
			log.error("Exception invoking periodic operation: ", t);
		} finally {
			if (container instanceof Context) {
				((Context) container).unbind(false, originalClassLoader);
		   }
		}
	}
}

StandardContext的backgroundProcess()方法:注意执行完之后还会调用父类ContainerBase的backgroundProcess()方法。

public void backgroundProcess() {

	if (!getState().isAvailable())
		return;

	Loader loader = getLoader();
	if (loader != null) {
		try {
		
			// 实现热加载
			loader.backgroundProcess();
		} catch (Exception e) {
			log.warn(sm.getString(
					"standardContext.backgroundProcess.loader", loader), e);
		}
	}
	Manager manager = getManager();
	if (manager != null) {
		try {
			manager.backgroundProcess();
		} catch (Exception e) {
			log.warn(sm.getString(
					"standardContext.backgroundProcess.manager", manager),
					e);
		}
	}
	WebResourceRoot resources = getResources();
	if (resources != null) {
		try {
			resources.backgroundProcess();
		} catch (Exception e) {
			log.warn(sm.getString(
					"standardContext.backgroundProcess.resources",
					resources), e);
		}
	}
	InstanceManager instanceManager = getInstanceManager();
	if (instanceManager instanceof DefaultInstanceManager) {
		try {
			((DefaultInstanceManager)instanceManager).backgroundProcess();
		} catch (Exception e) {
			log.warn(sm.getString(
					"standardContext.backgroundProcess.instanceManager",
					resources), e);
		}
	}
	
	// 调用父类ContainerBase的backgroundProcess()方法
	super.backgroundProcess();
}

WebappLoader#backgroundProcess:

public void backgroundProcess() {
	// 如果Context配置了reloadable =true,且文件已修改
	if (reloadable && modified()) {
		try {
			Thread.currentThread().setContextClassLoader
				(WebappLoader.class.getClassLoader());
			if (context != null) {
				// 调用StandardContext的reload()进行热加载
				context.reload();
			}
		} finally {
			if (context != null && context.getLoader() != null) {
				Thread.currentThread().setContextClassLoader
					(context.getLoader().getClassLoader());
			}
		}
	}
}

StandardContext#reload

public synchronized void reload() {
	
	// 设置暂停,停止接收新的请求
	// Stop accepting requests temporarily.
	setPaused(true);

	try {
	
		// 调用stop方法,停止context
		stop();
	} catch (LifecycleException e) {
		log.error(
			sm.getString("standardContext.stoppingContext", getName()), e);
	}

	try {
	
		// 调用start,重新启动context
		start();
	} catch (LifecycleException e) {
		log.error(
			sm.getString("standardContext.startingContext", getName()), e);
	}
	
	// 设置开启,重新接收请求
	setPaused(false);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值