前言
看完《通过tomcat源码查看其如何实现应用相互隔离》, 关于tomcat是如何做到热部署的,相信不用说也能猜到个十之八九。简单讲就是定期检查是否需要热部署,如果需要,则将类装载器也重新装载,并且去重新装载其他相关类。
代码分析
首先来看一个后台的定期检查,该定期检查是StandardContext的一个后台线程,会做reload的check,过期session清理等等,这里的modified实际上调用了WebappClassLoader中的方法以判断这个class是不是已经修改。注意到他调用了StandardContext的reload方法。
- public void backgroundProcess() {
- if (reloadable && modified()) {
- try {
- Thread.currentThread().setContextClassLoader
- (WebappLoader.class.getClassLoader());
- if (container instanceof StandardContext) {
- ((StandardContext) container).reload();
- }
- } finally {
- if (container.getLoader() != null) {
- Thread.currentThread().setContextClassLoader
- (container.getLoader().getClassLoader());
- }
- }
- } else {
- closeJARs(false);
- }
- }
那么reload方法具体做了什么?非常简单,就是tomcat lifecycle中标准的启停方法stop和start,别忘了,start方法会重新造一个WebappClassLoader并且重复loadOnStartup的过程(查看“ 通过tomcat源码查看tomcat如何实现应用相互隔离 ”),从而重新加载了webapp中的类,注意到一般应用很大时,热部署通常会报outofmemory: permgen space not enough之类的,这是由于之前加载进来的class还没有清除而方法区内存又不够的原因
- public synchronized void reload() {
-
- // Validate our current component state
- if (!started)
- throw new IllegalStateException
- (sm.getString("containerBase.notStarted", logName()));
-
- // Make sure reloading is enabled
- // if (!reloadable)
- // throw new IllegalStateException
- // (sm.getString("standardContext.notReloadable"));
- if(log.isInfoEnabled())
- log.info(sm.getString("standardContext.reloadingStarted",
- getName()));
-
- // Stop accepting requests temporarily
- setPaused(true);
-
- try {
- stop();
- } catch (LifecycleException e) {
- log.error(sm.getString("standardContext.stoppingContext",
- getName()), e);
- }
-
- try {
- start();
- } catch (LifecycleException e) {
- log.error(sm.getString("standardContext.startingContext",
- getName()), e);
- }
-
- setPaused(false);
-
- }