解决 ClassNotFoundException : com.sun.faces.config.ConfigureListener

最近接手了一个年代久远的项目,因为对 java 栈不太熟悉,走了很多弯路, 比如某日部署代码后运行 tomcat 就会报这个错误,这个问题困扰了我好多天, 记录一下当时是如何解决的,供大家参考

1 环境

因为是旧项目,各种工具都比较旧了

  • jdk 1.6
  • MyEclipse 8.5
  • tomcat 5.5

2 问题

在这个项目上已经开发了一周的时间,这一周内部署修改后的代码到服务器都还挺正常, 但是从某日开始,部署新代码调试时,每次 tomcat 都会报以下错误:

ClassNotFoundException : com.sun.faces.config.ConfigureListener

3 解决

3.1 依赖项

这看上去非常像是缺少了一些依赖项,于是立即对比开发目录和部署目录, 看看有没有没复制过去的 jar 包,确实有,但是复制过去以后,问题依旧, 其实怀疑依赖项只是根据表象报错做出的推测,这一周都可以正常运行,而且也没有增加新的依赖项, 依赖项出问题的机会很低

3.2 检查代码修改

依赖项没有问题,那么最大的可能就是最近代码改动过大引起的了,可是我看了一下, 短期修改的内容都是业务逻辑,应该不会有这么大的影响, 不过我还是试着将代码恢复到前两天正常时的版本,问题依旧,所以代码本身有问题的可能性也很低

3.3 直接运行 tomcat

接下来怀疑 MyEclipse 没有正常启动 tomcat 服务器,于是自己试了下命令行直接启动 tomcat, 依然报错

3.4 求助 google

搜索这个 exception 和类名,一般看到的解决方案有以下几种:

3.4.1 缺少依赖项

虽然已经基本排除了这个可能,但还是又试了一下,无果

3.4.2 依赖项冲突

的确之前正常的时候 tomcat 也会提示忽略了一些 jar 包,但是还是和前面提到那样, 依赖项这周没有任何改动,出问题的机会很低,当然也试着删去了提示无效的包,依然没有解决问题

3.4.3 修改 jdk 版本

这个听上去就不怎么靠谱,可能初次运行代码出现这种问题可以考虑这种解法, 我是之前可以正常运行的,而且也不可能修改 jdk 的版本,忽略

3.4.4 重新部署

走到这里我也基本判定是 tomcat 的缓存问题,或者是 MyEclipse 部署时漏掉了某些文件,于是我尝试手动复制到 tomcat 目录,还是不行。

后来我拿出了之前正确运行的 tomcat 备份覆盖掉现在有问题的 tomcat, 然后重新部署上去,居然正确运行了,所以我基本可以确定是 tomcat 缓存的问题, 但不知道是具体哪里出了问题,为了以防万一,我把正常运行的 tomcat 也做了版本控制, 这样一旦有问题,我可以立即 revert 会之前正常的版本, 同时也对哪些文件做了修改一目了然

3.5 后续 Part 1

在这个项目的第二周内,又陆续碰到了几次相同的错误,而且直接重新部署也不能解决问题, 不过因为有对 tomcat 做版本控制,每次遇到问题,只要 revert 对 tomcat 的修改, 然后重新部署即可,多次 revert 后,我注意到了一个文件 tldCache.ser , 印象中基本上每次有问题时,都要 revert 它,带上这个文件名,我又去搜索了下这个问题, 终于在 这里 找到了问题的原因和解法,看上去是 tomcat 保存了一份旧的 listener 缓存 , 导致程序在启动时,没有找到正确的引用对象,正确的解法其实是 清空 tomcat 的 work 目录

3.6 后续 Part 2

之后的几次清空 work 目录还是会报相同的问题,感觉最有效的办法还是 revert tldCache.ser 文件

4 结论

终于理清了问题的来龙去脉,对于我这样的 java 初学者来说,其实挺不易的, 因为很难把这个错误和某个缓存文件联系在一起,而且简单的搜索也没办法直接定位到问题, 所以记录一下自己的做法给大家参考,我觉得这次问题的解决过程,给我帮助最大的是 git, 依靠对 tomcat 的版本控制,我终于注意到了问题的来源, 大家也可以对正常运行的环境做一下版本控制,这样,当环境不再正常时, 我们也可以通过和正常环境的比较,来定位问题的所在,当时我确实也觉得自己挺夸张的, 连 tomcat 也上 git 了,不过确实有帮助啊