一个离奇的ArrayIndexOutOfBoundsException异常的排查过程
今天同事遇到了一个离奇的ArrayIndexOutOfBoundsException,找我协助定位,定位的过程很有意思,故而记录一下。
先按时序复盘一下
项目原先可正常运行。
没有修改任何依赖的情况下,从另一个项目移植了工具类
BeanValidationUtil
后,报如下异常:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:307) | Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: Failed to readcandidate component class: file [/Users/xxxxxxxxx/BeanValidationUtil.class];nested exception is java.lang.ArrayIndexOutOfBoundsException: 48959
atorg.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:260)
atorg.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:242)
atorg.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(ComponentScanBeanDefinitionParser.java:84)
atorg.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73)
atorg.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1419)
atorg.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1409)
atorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:184)
atorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:140)
atorg.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:111)
atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
atorg.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174)
atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209)
atorg.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)
atorg.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125)
atorg.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94)
atorg.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:131)
atorg.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:522)
atorg.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:436)
atorg.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:384)
atorg.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:283)
atorg.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
atorg.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:5135)
atorg.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5658)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:145)
atorg.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:1015)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:991)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:2015)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
atorg.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
atcom.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
atcom.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
atorg.apache.catalina.mbeans.MBeanFactory.createContext(MBeanFactory.java:789)
atorg.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:573)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
atorg.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
atcom.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
atcom.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
atjavax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468)
atjavax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
atjavax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309)
atjavax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401)
atjavax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
atsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:324)
at sun.rmi.transport.Transport$1.run(Transport.java:200)
at sun.rmi.transport.Transport$1.run(Transport.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
atsun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
atsun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
atsun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683)
at java.security.AccessController.doPrivileged(Native Method)
atsun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ArrayIndexOutOfBoundsException: 48959
at org.springframework.asm.ClassReader.readUnsignedShort(UnknownSource)
at org.springframework.asm.ClassReader.accept(Unknown Source)
at org.springframework.asm.ClassReader.accept(Unknown Source)
at org.springframework.core.type.classreading.SimpleMetadataReader.<init>(SimpleMetadataReader.java:54)
atorg.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:80)
atorg.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(CachingMetadataReaderFactory.java:101)
atorg.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:236)
... 68 more
造成异常的工具类
1 | /** |
分析
如代码所示,BeanValidationUtil
是个工具类,根本不在Spring容器上下文里,但异常栈却报到Spring的包里去了。
- 由于项目没有修改依赖,所以包冲突问题不太可能出现(这个项目原先也使用JSR349做Bean Validation),而且冲突的话异常应该是NoClassDefFoundError之类的异常。
- 尝试降低Hibernate Validation的版本到4.x,故障依旧。
- 百度、谷歌类似异常,无果。
经过20分钟的源码定位也没找到问题所在,于是我尝试逐步删除BeanValidationUtil的代码。发现当把lambda语法删光之后,项目就能正常启动了。
突然灵光一现,问同事 : “这TM是不是个非常古老的项目啊?”
同事:“对啊,四五年了吧……”
于是分析了下pom.xml,发现用的是Spring 3 。隐约记得Spring 3不完全兼容JDK8,这个类中使用了Java 8的语法,所以导致了问题。
结果确认
既然猜测是Spring 3和Java 8不兼容导致,故而在搜索时,将关键词改为:spring 3 java 8 ArrayIndexOutOfBoundsException
,果然印证了自己的想法。
- ArrayOutOfBoundsException on Bean creation while using Java 8 constructs
- Spring BeanDefinitionStoreExcept-nested exception is java.lang.ArrayIndexOutOfBoundsException: 53804
反思
犯了经验主义错误,基于Spring 3的项目已经三四年没有见过了(Dubbo不算,哈哈哈。因为Dubbo当初的版本虽然依赖了Spring 3,但其实实际项目一般都会exclude掉,换上Spring 4),一直以为是个Spring 4的项目,没有从Spring版本与JDK的兼容性的方向上去考虑。
浪费了半小时。
评论系统未开启,无法评论!