使用Google Guava缓存时遭遇com.google.common.cache.RemovalCause类未找到错误的排查咨询
排查Guava缓存RemovalCause类加载失败的问题
这问题我之前帮不少开发者排查过类似情况——虽然你已经确认guava-30.1-jre.jar里存在RemovalCause类,但NoClassDefFoundError很多时候不是Jar包缺失的问题,而是类加载器隔离或依赖冲突这类更隐蔽的原因导致的。咱们一步步来拆解排查:
1. 优先排查依赖冲突(最常见原因)
很多时候项目里会间接引入旧版本的Guava,导致类加载时优先加载了旧版本的类(即便旧版本有RemovalCause,也可能因类加载器上下文不一致触发错误)。
- 用依赖分析工具查看完整依赖树:
- Maven项目执行:
mvn dependency:tree | grep guava - Gradle项目执行:
./gradlew dependencies | grep guava
- Maven项目执行:
- 如果发现多个版本的Guava(比如18.x、20.x这类旧版本),需要在依赖管理里强制指定使用30.1-jre版本:
- Maven中在
<dependencyManagement>里锁定版本:<dependencyManagement> <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1-jre</version> </dependency> </dependencies> </dependencyManagement> - Gradle中用
force关键字强制版本:configurations.all { resolutionStrategy.force 'com.google.guava:guava:30.1-jre' }
- Maven中在
2. 检查类加载器隔离问题
如果是Web应用(如Tomcat、Jetty)或模块化项目(Jigsaw模块),类加载器的隔离规则可能导致RemovalCause和LocalCache被不同加载器加载,从而触发错误。
- 在报错代码附近添加调试代码,打印类加载器信息:
// 打印LocalCache的类加载器 System.out.println("LocalCache classloader: " + LocalCache.class.getClassLoader()); try { // 尝试用LocalCache的类加载器加载RemovalCause Class<?> rcClass = Class.forName( "com.google.common.cache.RemovalCause", true, LocalCache.class.getClassLoader() ); System.out.println("RemovalCause loaded with classloader: " + rcClass.getClassLoader()); } catch (ClassNotFoundException e) { e.printStackTrace(); } - 若两个类加载器不一致:
- Web应用:检查容器lib目录是否存在Guava Jar,若有则删除,让应用优先使用WEB-INF/lib下的版本;
- 模块化项目:确保
module-info.java中正确引入Guava模块:module your.module.name { requires com.google.common; }
3. 排查字节码增强工具的干扰
如果项目使用了AspectJ、CGLIB、ByteBuddy这类字节码增强工具,或SkyWalking、Pinpoint这类监控工具,它们可能在修改Guava类的过程中破坏了RemovalCause的加载逻辑。
- 临时禁用这些工具,重新部署应用,若问题消失,需调整工具配置,排除Guava的
com.google.common.cache包不被增强。
4. 验证Jar包的实际可访问性
虽然你用jar -tf确认了类存在,仍可做个独立测试排除Jar包本身或环境权限问题:
- 写一个极简测试类:
import com.google.common.cache.RemovalCause; public class GuavaTest { public static void main(String[] args) { System.out.println("Successfully loaded RemovalCause: " + RemovalCause.class); for (RemovalCause cause : RemovalCause.values()) { System.out.println("- " + cause); } } } - 编译并运行:
javac -cp guava-30.1-jre.jar GuavaTest.java java -cp .:guava-30.1-jre.jar GuavaTest
如果测试正常运行,说明Jar包本身没问题,问题出在你的应用环境中,回到前面的排查步骤即可。
5. 检查JVM类加载参数
查看应用启动时的JVM参数,确认是否设置了-Xbootclasspath、-javaagent这类干扰类加载的参数——比如-Xbootclasspath包含旧版本Guava时,会优先加载系统类路径下的类,导致冲突。
内容的提问来源于stack exchange,提问作者Ravi Soni




