记录一次生产环境中Tomcat 启动服务报错的排查修复过程,经验总结。
排查过程
根据Catalina.out
日志的报错记录进行逐步排查问题。
问题1
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'multipartResolver': Failed to introspect bean class [org.springframework.web.multipart.commons.CommonsMultipartResolver] for lookup method metadata: could not find class that it depends on; nested exception is java.lang.NoClassDefFoundError: org/apache/commons/fileupload/FileItemFactory.
Spring Bean 初始化失败:错误栈信息中显示了
BeanCreationException
,表示 Spring 在初始化multipartResolver
Bean 时遇到问题。缺少依赖类:最根本的原因是
java.lang.NoClassDefFoundError
,提示缺少org/apache/commons/fileupload/FileItemFactory
类。这个类属于 Apache Commons FileUpload 库,CommonsMultipartResolver
依赖它来处理文件上传。
- 检查依赖:确认项目的依赖中包含
commons-fileupload
。如果项目使用 Maven 或 Gradle,确保commons-fileupload
依赖已经正确配置。例如,在 Maven 中可以添加以下依赖:
1 | <dependency> |
问题2
org.springframework.amqp.rabbit.connection.CachingConnectionFactory - Could not get host name, using ‘localhost’ as default value
java.net.UnknownHostException: CustomServer: CustomServer: unknown error
at java.net.InetAddress.getLocalHost(InetAddress.java:1505)
错误日志显示
java.net.UnknownHostException: CustomServer: unknown error
。这是因为生产环境中未能正确解析主机名CustomServer
。解决方法:确保
CustomServer
主机名在生产环境的/etc/hosts
文件中被正确配置,或者在 DNS 服务器中解析。如果无法设置此主机名,可以尝试将 AMQP 连接的hostname
明确设为localhost
或目标 IP 地址,而不是依赖默认主机名。
因为之前这台Tomcat 部署的服务都正常,我记得之前有同事更改了主机名,但是这个过程中服务是没有重启,所以没有问题。这次重启Tomcat 就把这个问题暴露出来了。
[[编程日志/images/生产环境Tomcat 部署服务报错问题排查/bc96f46c85c7db0300757a7660a3f7ea_MD5.png|Open: Clip_2024-11-06_13-37-43.png]]
因此,增加了hosts 配置,这个问题就解决了。
问题3
registered the JDBC driver [com.alibaba.druid.proxy.DruidDriver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
这个问题,一直以为是JDBC 连接没有释放,但是从网上查看资料,说是Tomcat 误报的信息,不用搭理,一直排查了好久,期间我把另一台A 服务器上的Tomcat 整体拷贝过来启动,也是同样的问题,后来怀疑是B 服务器上的JDK 问题,但不确定,查阅Google 有篇博客厄舍屋下|解决:the JDBC Driver has been forcibly unregistered给出了提示,随查看日志,发现问题确定是 JDK 的问题。
localhost_access_log.2024-11-05.txt 文件报错内容如下
org.apache.catalina.core.StandardContext.filterStart Exception starting filter [javamelody]
java.lang.UnsatisfiedLinkError: /apps/infra/jdk1.8.0_77/jre/lib/amd64/libawt_xawt.so: libXrender.so.1: cannot open shared object file: No such file or directory
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
at java.lang.Runtime.load0(Runtime.java:809)
at java.lang.System.load(System.java:1086)
这个错误信息显示在启动 Java 应用程序时,缺少了一个本地库 libXrender.so.1
。这个库是 X11 的一部分,通常用于图形显示。在某些 Java 应用程序(如使用 Java AWT 或 Swing 的应用程序)中,需要这个库来进行图形渲染。
使用如下命令对比两台服务器,,查库文件是否存在
1 | ldconfig -p | grep libXrender |
相比B服务器,A服务有如下结果
要解决这个问题,可以按照以下步骤操作:
1. 安装 libXrender
库
1 | # Ubuntu |
2. 自定义Tomcat 的JDK
但是因为是生产环境,不确定安装后有没有影响,因此我选择了方式2,将A 服务器的JDK 拷贝到B 服务器,然后在Tomcat配置文件中指定JDK版本运行程序。
修改Tomcat的配置文件setclasspath.sh
、catalina.sh
,添加java_home
、jre_home
的环境变量。
1 | # tomcat bin 目录 |
修改完,重启Tomcat 问题解决,发现Tomcat 使用的是我们自定义的JDK。