【开发笔记】Spring MVC框架升级错误:找不到ReflectionUtils.doWithLocalFields方法
问题
在升级Spring MVC项目版本(目标版本是4.3.16)后,启动Tomcat输出如下错误信息:
ERROR | Context initialization failed
java.lang.NoSuchMethodError: org.springframework.util.ReflectionUtils.doWithLocalFields(Ljava/lang/Class;Lorg/springframework/util/ReflectionUtils$FieldCallback;)V
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.buildPersistenceMetadata(PersistenceAnnotationBeanPostProcessor.java:418)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findPersistenceMetadata(PersistenceAnnotationBeanPostProcessor.java:397)
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(PersistenceAnnotationBeanPostProcessor.java:333)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:929)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:512)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:220)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:619)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:465)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:443)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:325)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4745)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5207)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
分析
通过搜索【doWithLocalFields java.lang.NoSuchMethodError】,得到类似的条目有:
(1)https://*.com/questions/46056321/spring-java-lang-nosuchmethoderror-org-springframework-util-reflectionutils-dow
(2)https://www.cnblogs.com/sxdcgaq8080/p/8022121.html(参考(1)中的结论:4.2以后上面报错的方法就被提到了spring-core架包中而不是在orm架包中,所以,需要将spring-orm架包的版本降低到<4.2以下)
(3)https://bbs.csdn.net/topics/392078670?page=1(仅提问,未解决)
搜到的条目并不是很多,看来并不是很多开发者倾向于升级框架版本(虽然最新的Spring框架版本都到了5.0+)。
虽然看完(1)和(2)感觉结论并不靠谱,并不会是4.2版本这个梗。
显而易见,框架是整体的,不可能就其中的某一个jar包为低版本吧?!
即便这样,(3)中的一个操作点醒了我,决定查看一下这个工具类的定义看看。
发现
在eclipse中使用快捷键Ctrl+Shift+t,检索ReflectionUtils这个工具类的引用,结果是大吃一惊!
如上图,居然发现有2个该类的定义!其中1个类定义居然在Active MQ的jar包中!
再搜索doWithLocalFields ActiveMQ,得到类似的条目:
(1)https://www.oschina.net/question/2670896_2242950(但没有得到解决方法)
问题定位在ActiveMQ的jar包中,打开该jar包,果不其然:
顿时有2个疑问:
(1)为啥ActiveMQ的jar包中包含了Spring框架的代码?
(2)为啥旧版的ActiveMQ的jar包没有出现这个问题?
在ActiveMQ的官网上(http://activemq.apache.org/)似乎找到了根源:
从5.12.0版本开始,ActiveMQ的jar包中开始包含spring框架的部分代码(部分工具类),其中的代码是否与Spring官方发布的代码是否同步就不由得知了。
解决
使用ActiveMQ的5.12版之前的最后版本(5.11.4)替换较新5.14.5版本。
总结
(1)该问题属于jar包冲突的问题
(2)对于(1)需要进一步了解冲突类/接口的定义、引用情况,记住使用快捷键Ctrl+Shift+t
(3)不要一口气全部替换,可以分步替换,这样可以快速定位。