Tomcat 配置导致启动时,项目加载两次的解决办法

  |   0 评论   |   0 浏览

现象:

Tomcat 在启动的时候,由于配置原因,导致工程会被加载两次,很容易出现内存溢出。如果有定时任务,也可能导致定时任务执行两次,从而出现问题。

原因:

在 tomcat/conf/server.xml 配置虚拟目录引起,如下配置:

<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
      <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" 
	   pattern="%h %l %u %t &quot;%r&quot; %s %b" 
	   prefix="localhost_access_log" suffix=".txt"/>
 
      <Context docBase="solo" path="/" reloadable="true" />
</Host>

首先介绍下 appBase 与 docBase 的区别

  • appBase 是指定虚拟主机的目录,可以指定绝对目录,也可以指定相对于 Tomcat 目录的相对目录,如果没有此项,默认为 webapps
  • docBase 是指定 Web 应用的文件路径,可以给定绝对路径,也可以给定相对于 Host 的 appBase 属性的相对路径;如果 Web 应用采用开放目录结构,那就指定 Web 应用的根目录;如果 Web 应用是个 WAR 文件,那就指定 WAR 文件的路径

分析:

  1. 根据 Tomcat 规则,当为 Host 容器设置了 appBase 属性时,Tomcat 会在启动时自动加载 appBase 指定目录下的所有合法工程;
  2. 同时 Context 的 docBase 属性设置了 Tomcat 默认工程, 所以指定的 工程又会被加载一次;
  3. 根据 server.xml 配置,Tomcat 首先根据的配置内容生成第一个 StandardContext 对象,加载一次项目。
  4. 然后,再根据 Host/appBase 的配置对 webapps 下面的项目生成第二个 StandardContext,再加载一次项目。

Tomcat 针对同一项目生成两个 StandardContext 的原因就是因为他们的名字不同,Tomcat 认为是两个 Context,所以加载了两次。

上面,我们在 Host 标签里配置了 appBase="webapps",Tomcat 加载了一次应用。同时, 在里配置了一次 docBase,Tomcat 又加载了一次。 从而,导致项目会加载二次。

解决方法:

方法一

直接把项目放到 webapps 下,指定 appBase="webapps",不指定配置内容,即注释掉

方法二

不把项目放入 webapps 下,在 Tomcat 目录下新建文件夹,如 Solo,去掉 appBase 设置(经测试,设置 appBase="",貌似也不行),然后配置标签:

<Context docBase="D:/Tomcat/solo" path="" reloadable="true"/>   

方法三

直接把项目目录放到 webapps 下,并修改项目名称为 ROOT,指定 appBase="webapps",不指定配置内容,即注释掉

结论,如果 Tomcat 仅加载了少数的项目,可以使用方法一、三。另外,方法二也存在弊端,即如果项目中的链接或者图片是绝对路径的话,那么带有项目名称的绝对路径是无法正常使用的。

参见:https://blog.csdn.net/mrliar17/article/details/80898914
https://segmentfault.com/a/1190000002985203