Spring 5.0.1项目启动报错NoSuchMethodError:BeanDefinitionParserDelegate.getEnvironment()
这个问题我之前排查过好几次,本质就是类路径下同时存在Spring 4.x和5.x的类,类加载器优先加载了旧版本的类,才会出现明明用了5.0.1却触发4.x方法调用的诡异情况。
为什么会出现这个异常?
Spring 5.x版本已经移除了org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.getEnvironment()这个方法,但4.3.x版本的ComponentScanBeanDefinitionParser类里确实有调用这个方法的代码。当你的项目类路径里同时存在这两个版本的Spring类时,Tomcat的类加载机制可能会先加载到4.x版本的ComponentScanBeanDefinitionParser,它去调用已经被移除的方法,自然就抛出NoSuchMethodError了。
可能的冲突来源及解决方法
依赖传递引入了Spring 4.x
很多第三方依赖(比如一些老的工具包、持久层框架)可能还依赖Spring 4.x,Maven/Gradle在拉取依赖时会自动把这些旧版本的Spring jar也下载下来。你可以用命令排查:# Maven项目查看依赖树 mvn dependency:tree # Gradle项目查看依赖树 gradle dependencies找到所有带有
spring-*且版本为4.x的依赖,在你的pom.xml里用<exclusions>标签排除掉这些旧版本。比如:<dependency> <groupId>某个第三方组ID</groupId> <artifactId>某个第三方 artifactID</artifactId> <version>版本号</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> <!-- 排除所有相关的Spring 4.x依赖 --> </exclusions> </dependency>Tomcat自身lib目录存在旧Spring jar
Tomcat的类加载顺序是先加载自身lib目录下的类,再加载webapp的WEB-INF/lib。如果Tomcat的lib里放了Spring 4.x的jar,不管你webapp里用的是5.x,都会优先加载旧版本。
解决方法:检查Tomcat的$CATALINA_HOME/lib目录,删除所有Spring相关的jar(Spring jar应该放在webapp的WEB-INF/lib里,不要放在Tomcat全局lib下)。项目部署目录残留旧jar
如果你之前部署过用Spring 4.x的版本,Tomcat的webapps目录下的项目文件夹里,WEB-INF/lib可能还残留着旧的Spring jar,和新的5.x jar共存。
解决方法:彻底清理Tomcat的webapps下的项目目录,同时清理项目的target(Maven)或build(Gradle)目录,重新编译打包后再部署。
验证方法
部署完成后,你可以:
- 打开webapp的
WEB-INF/lib目录,检查所有spring-*.jar的版本,确保都是5.0.1.RELEASE; - 用
javap命令查看加载的类版本,比如:
看字节码里的方法调用,确认是不是Spring 5.x的实现。javap -c org.springframework.context.annotation.ComponentScanBeanDefinitionParser
内容的提问来源于stack exchange,提问作者a Learner

