近期在做甲方的项目,里面用的技术体系很老,非 spring boot项目,是 jdk 8 + spring + spring mvc + tomcat + jsp 的方式。遇到了一个问题,在这里记录一下。
自己加了一部分代码功能,启动后报错,如下
24-Jun-2026 20:34:58.436 严重 [RMI TCP Connection(2)-127.0.0.1] org.apache.catalina.core.StandardContext.listenerStart Exception sending context initialized event to listener instance of class [com.sinoservices.xframework.core.context.ContextLoaderListener] org.springframework.beans.factory.BeanDefinitionStoreException: Failed to read candidate component class: URL [jar:file:/F:/code/pj-oms/orr-java-webapps/target/orr-java-webapps-0.0.1-SNAPSHOT/WEB-INF/lib/orr-java-0.0.1-SNAPSHOT.jar!/com/sinoservices/orr/edi/send/bean/EipBusinessPriceRequest.class]; nested exception is java.lang.IllegalArgumentException: INVOKESPECIAL/STATIC on interfaces require ASM 5 at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:290) at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(ClassPathBeanDefinitionScanner.java:242) at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(ComponentScanBeanDefinitionParser.java:84) at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1438) at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1428) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:195) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:139) at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:108) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334) at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209) at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:125) at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:94) at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130) at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:537) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:451) at com.sinoservices.xframework.core.context.module.Module.start(SourceFile:77) at com.sinoservices.xframework.core.context.archives.ModuleDeploymentArchives.buildDeploymentArchive(SourceFile:70) at com.sinoservices.xframework.core.context.archives.DeploymentArchives.scanArchives(SourceFile:147) at com.sinoservices.xframework.core.context.archives.DeploymentArchives.deploy(SourceFile:164) at com.sinoservices.xframework.core.context.ContextLoaderListener.contextInitialized(SourceFile:124) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4817) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5283) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:754) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:730) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734) at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1736) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:483) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:432) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at com.sun.jmx.remote.security.MBeanServerAccessController.invoke(MBeanServerAccessController.java:468) at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468) at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76) at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309) at java.security.AccessController.doPrivileged(Native Method) at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1408) at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:346) 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) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.IllegalArgumentException: INVOKESPECIAL/STATIC on interfaces require ASM 5 at org.springframework.asm.MethodVisitor.visitMethodInsn(Unknown Source) at org.springframework.asm.ClassReader.a(Unknown Source) at org.springframework.asm.ClassReader.b(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.<init>(SimpleMetadataReader.java:64) at org.springframework.core.type.classreading.SimpleMetadataReaderFactory.getMetadataReader(SimpleMetadataReaderFactory.java:80) at org.springframework.core.type.classreading.CachingMetadataReaderFactory.getMetadataReader(CachingMetadataReaderFactory.java:102) at org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(ClassPathScanningCandidateComponentProvider.java:266) ... 72 more只知道是asm字节码增强的问题,具体哪里的问题不清楚。
有一个同事协助看了一下,说是我写的代码方式的问题。如下
Map<String, PurchaseItem> materialCodeAndPurchaseItemMap = ListUtils.emptyIfNull(itemList).stream().collect(Collectors.toMap(PurchaseItem::getProductCode, Function.identity()));后面我改成了非 java stream 的方式,启动正常,接下来我思考,为什么出现了这个问题?
INVOKESTATIC 这个字节码在 jvm 中原来就有的,突然间报这个问题不应该。
问了AI,这么回复的
在 Java 8 之前,接口中只能有抽象方法,
invokestatic指令只用于调用普通类中的静态方法。Java 8 的一个重大语言特性,就是允许在接口中定义静态方法。为了支持这个新特性,JVM 规范修改了invokestatic指令,使其能够识别并调用接口中定义的静态方法。这也就是为什么你在使用
Function.identity()(它是java.util.function.Function接口的静态方法)时,会触发你之前遇到的 ASM 错误。老版本的 ASM(低于 5.0)不知道 Java 8 这种新玩法,把它当成了错误用法。
又看了一下 asm 与 jdk 的对应关系
| ASM 版本 | 主要支持的 Java 版本 | 字节码版本 |
|---|---|---|
| ASM 4.x | Java 7 | 51 |
| ASM 5.x | Java 7,对 Java 8 支持不完整 | 51 |
| ASM 6.x | Java 8 | 52 |
| ASM 7.x | Java 9 | 53 |
| ASM 8.x | Java 11 | 55 |
| ASM 9.x | Java 15 - Java 17, 及更高版本 | 59 - 61+ |
| ASM 10.x | Java 17 | 61 |
看这个意思,如果 asm 升级到 6.x 的话就正常了,经过实际验证,启动正常。
鉴于目前甲方的项目里加 maven 依赖和配置都需要告知一下,为了不给自己找麻烦,就只能这样了。