背景介绍,项目通过maven来管理,有项目依赖关系,使用eclipse的springSource tool suite来编译
项目在执行junit测试时报如下错误:
Exception in thread "main" java.lang.NoSuchMethodError: org.springframework.beans.factory.annotation.InjectionMetadata.<init>(Ljava/lang/Class;)V
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.findResourceMetadata(CommonAnnotationBeanPostProcessor.java:318)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessMergedBeanDefinition(CommonAnnotationBeanPostProcessor.java:277)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors(AbstractAutowireCapableBeanFactory.java:798)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:493)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:880)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:596)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:365)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83)
at TestSpring.main(TestSpring.java:12)
分析:找不到InjectionMetadata的构造函数(Ljava/lang/Class;)
查看InjectionMetadata方法声明,项目中maven使用spring3.0
spring2.5构造函数:InjectionMetadata(Class targetClass)
spring3.0构造函数:InjectionMetadata(Class<?> targetClass, Collection<InjectionMetadata.InjectedElement> elements)
错误原因很清楚:spring-context.jar的版本使用的2,调用InjectionMetadata的构造函数(Ljava/lang/Class;),问题是spring-context.jar的2版本eclipse从哪找的
查看了pom.xml依赖关系图,未找到引用spring2版本
查找项目依赖的mavenlib包也没有spring2相关jar
为了防止是Junit造成,改用main函数调用,错误依然
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
}
用类的加载顺序先于jar包,强制版本
直接在项目的源代码中加入spring的CommonAnnotationBeanPostProcessor类源代码,根据类的加载顺序会加载本类,确实不报找不到方法了。
小插曲:CommonAnnotationBeanPostProcessor中有引用 import javax.ejb.EJB;怀疑是不是因为没有javax.ejb.EJB相关jar包引起的,如果是因为没有javax.ejb.EJB相关jar,那tomcat下为什么能正常引用,除非tomcat下有相关jar包,后来从tomcat下找到apache-tomcat-6.0.26\lib\annotations-api.jar,把annotations-api.jar引用eclipse编译路径下,CommonAnnotationBeanPostProcessor不报错了,但删除CommonAnnotationBeanPostProcessor类,错误依然。说明还是存在jar包冲突。
还说明一个java语言的一个规定:如果加载的Class文件中引用了不存在的其它类,是可以正常加载的,除非调用了相关方法才会报错。这只是个小插曲,和错误原因无关。
删除所有依赖,全部手工加载外部jar
改动前
改动后,jar包从maven编译完后的target下取得
没有错误了,通过试错,最终发现是因为 Web App Libraries造成的问题
附上 Web App Libraries的具体内容:
最终原因分析:eclipse的 Web App Libraries和maven的编译机制存在差异
在maven体系中:通过在maven中认为无依赖的可能会通过Web App Libraries最终达到eclipse的编译路径中。
只要对应的项目处理打开有状态中,如果关闭dao项目,就不会报错。只要打开依赖的项目,maven中的exclusions对于eclipse是失效的。