目录
1. 项目场景
最近搞了一个老项目采用tomcat war形式部署,Idea项目本地启动和windows tomcat8启动没问题,但是部署到linux上后无法启动成功。
2. 问题描述
项目部署到linux上后无法启动成功,多次打包后上传war包启动,偶尔可以启动成功,非常奇怪。
查看日志发现 privCache bean无法注入ioc。
3. 原因分析
3.1 日志分析
主要日志:
Error creating bean with name ‘privCache’ defined in URL [jar:file:/data/apache-tomcat-8.5.68/webapps/gas/WEB-INF/lib/cloud-priv-service-2.0.6-patch-1.jar!/spring/spring-config-priv.xml]: Invocation of init method failed; nested exception is java.lang.NullPointerException
Caused by: java.lang.NullPointerException
at com.gsafety.cloudframework.common.base.util.SpringUtil.getBean(SpringUtil.java:38)
at com.gsafety.cloudframework.priv.util.PrivCacheUtil.initDbPriv(PrivCacheUtil.java:37)
at com.gsafety.cloudframework.priv.util.PrivCacheUtil.initPrivInfo(PrivCacheUtil.java:27)
- 分析:项目中使用了SpringUtil.getBean获取bean的方式,但是此时这个bean并没有被注入ioc,所以拿不到对象,导致启动失败。
- 对比成功日志和失败日志
二者bean的加载顺序不一致。初步怀疑无法启动成功和bean的加载顺序有关。那么为什么windows和本地没有问题,linux会出现问题?
3.2 jar包加载顺序
- $java_home/lib 目录下的java核心api
- $java_home/lib/ext 目录下的java扩展jar包
- java -classpath/-Djava.class.path所指的目录下的类与jar包
- $CATALINA_HOME/common目录下按照文件夹的顺序从上往下依次加载
- $CATALINA_HOME/server目录下按照文件夹的顺序从上往下依次加载
- $CATALINA_BASE/shared目录下按照文件夹的顺序从上往下依次加载
- 我们的项目路径/WEB-INF/classes下的class文件
- 我们的项目路径/WEB-INF/lib下的jar文件
- 同一文件夹,window上到下,linux下到上
原来windows和linux对jar的加载顺序是相反的,但是即使相反也不会导致bean注册不上,因为这个bean在lib下,应该首先被加载。而且日志中bean的加载是无序的。(类似 b.jar,a.jar,z.jar …)
3.3 关于tomcat WEB-INF/lib下类加载顺序问题
tomcat5-7对于WEB-INF/lib下的jar的搜索会按字母排序,tomcat8以上不会排序,依赖文件系统随机返回文件列表,这样的话tomcat8在不同的机器上可能出现运行时加载类混乱的问题,从而发生诡异的问题。
现在服务器上是tomcat8.x.x版本,所以类加载存在不确定性。导致SpringUtil.getBean获取不到bean的对象。
4. 解决方案
下载tomcat7.x.x版本进行部署,部署成功!tomcat-7.0.108 解压版
5. 存疑
linux tomcat8 在一定几率下可以成功启动。
怀疑是war在解压的过程中解压进度刚好是有序的或者刚好把存在问题的bean按序加载了,导致启动成功。
希望有相关经验的同行答疑。毕竟tomcat7已经被apache弃用了。
6. tomcat8 解决方案(没有效果)
网上找的解决方案,但是实测没有效果!
tomcat的conf目录下修改context.xml文件,加上如下语句就可以办到了:
<Resources>
<PreResources className="org.apache.catalina.webresources.FileResourceSet"
base="${catalina.base}/webapps/你的项目名称/WEB-INF/lib/提到前面来的冲突jar包名.jar"
webAppMount="/WEB-INF/lib/提到前面来的冲突jar包名.jar" />
</Resources>