Spring 3.1+OpenJDK11环境下类型转换及数组越界问题求助
- 运行环境:OpenJDK 11、Spring 3.1、Tomcat 8.5
初始代码与ClassCastException
编写了如下监听类:
import org.springframework.web.context.ContextLoaderListener; import org.springframework.web.context.WebApplicationContext; public class TomcatStopListener extends ContextLoaderListener { public void contextDestroyed(ServletContextEvent event) { try { WebApplicationContext context = (WebApplicationContext) event.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); // 后续代码省略 } catch (Exception e) { // 异常处理省略 } } }
运行时抛出类型转换异常:
java.lang.ClassCastException: org.springframework.beans.factory.BeanDefinitionStoreException incompatible with org.springframework.web.context.WebApplicationContext at com.nsn.servlets.TomcatStopListener.contextDestroyed(TomcatStopListener.java:28) at org.apache.catalina.core.StandardContext.listenerStop(StandardContext.java:4811) at org.apache.catalina.core.StandardContext.stopInternal(StandardContext.java:5467)
2022年9月26日更新:改用API后出现ArrayIndexOutOfBoundsException
改用WebApplicationContextUtils获取上下文:
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
抛出数组越界异常,栈信息如下:
Caused by: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 11560
at org.springframework.asm.ClassReader.readClass(Unknown Source)
at org.springframework.asm.ClassReader.accept(Unknown Source)
at org.springframework.asm.ClassReader.accept(Unknown Source)
at org.springframework.core.type.classreading.SimpleMetadataReader.(SimpleMetadataReader.java:59)
at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:80)
at org.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(CachingMetadataReaderFactory.java:101)
at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:237)
针对ClassCastException的问题
- 问题根源:Spring启动失败时,会将
BeanDefinitionStoreException存入WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE属性,而非正常的WebApplicationContext实例,直接强转触发类型转换异常。 - 修复方式:
- 先判断属性类型再转换:
Object attr = event.getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); if (attr instanceof WebApplicationContext) { WebApplicationContext context = (WebApplicationContext) attr; // 执行后续逻辑 } else { // 处理上下文初始化失败的情况,如记录日志 } - 利用父类方法直接获取:由于类继承自
ContextLoaderListener,可直接调用父类的getWebApplicationContext()方法,无需从ServletContext手动获取:@Override public void contextDestroyed(ServletContextEvent event) { try { WebApplicationContext context = getWebApplicationContext(); if (context != null) { // 执行销毁逻辑 } } catch (Exception e) { // 异常处理 } // 调用父类方法,保证Spring销毁流程正常执行 super.contextDestroyed(event); }
- 先判断属性类型再转换:
针对ArrayIndexOutOfBoundsException的问题
- 问题根源:Spring 3.1依赖的ASM版本过低,无法兼容OpenJDK 11的字节码格式(Java 11字节码版本为55.0,Spring 3.1默认ASM仅支持到Java 7的51.0版本),解析高版本字节码时出现数组越界。
- 修复方式:
- 升级Spring版本:Spring 3.1已停止维护,建议升级到支持Java 11的版本(如Spring Framework 5.3.x),这是最彻底的解决方案,同时能获得安全更新与新特性。
- 替换ASM依赖(临时方案):若暂时无法升级Spring,可手动将ASM版本升级到支持Java 11的版本(如ASM 9.x),但需注意此方式存在兼容性风险,需充分测试。
内容的提问来源于stack exchange,提问作者rajeshp808

