JAI ImageIO NoClassDefFoundError for RawImageInputStream

Roc*_*cky 3 jai javax.imageio

我对这个问题很困惑。我在 jai-imageio-core 上使用 1.3.0 版本,请检查下面的依赖关系,我完全无法从 jar 中找出一个类文件(RawImageReaderSpi)如何加载到 JVM 中,但未加载 RawImageInputStream。

我已经在 tomcat 7 容器中部署了我的 Spring Boot Web 服务。

这个问题是随机弹出的,我注意到当我重新启动 TC 容器并部署新版本的服务时,这个问题会间歇性地出现。

任何线索都受到高度赞赏。

我花了一天的时间试图找出问题所在,结果却觉得自己很愚蠢

<dependency>
    <groupId>com.github.jai-imageio</groupId>
    <artifactId>jai-imageio-core</artifactId>
    <version>1.3.0</version>
</dependency>

<dependency>
    <groupId>com.github.jai-imageio</groupId>
    <artifactId>jai-imageio-jpeg2000</artifactId>
    <version>1.3.0</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
java.lang.NoClassDefFoundError: com/github/jaiimageio/stream/RawImageInputStream
        在 com.github.jaiimageio.impl.plugins.raw.RawImageReaderSpi.canDecodeInput(RawImageReaderSpi.java:102) ~[jai-imageio-core-1.3.0.jar:1.3.0]
        在 javax.imageio.ImageIO$CanDecodeInputFilter.filter(ImageIO.java:567) ~[na:1.8.0_121]
        在 javax.imageio.spi.FilterIterator.advance(ServiceRegistry.java:821) ~[na:1.8.0_121]
        在 javax.imageio.spi.FilterIterator.(ServiceRegistry.java:815) ~[na:1.8.0_121]
        在 javax.imageio.spi.ServiceRegistry.getServiceProviders(ServiceRegistry.java:516) ~[na:1.8.0_121]
        在 javax.imageio.ImageIO.getImageReaders(ImageIO.java:646) ~[na:1.8.0_121]
        在 javax.imageio.ImageIO.read(ImageIO.java:1438) ~[na:1.8.0_121]
        在 javax.imageio.ImageIO.read(ImageIO.java:1352) ~[na:1.8.0_121]
        在 my-package.ab(a.java:155) ~[classes/:na]
        在 my-package.ab(a.java:181) ~[classes/:na]
        在 my-package.ab(a.java:84) ~[classes/:na]
        在 my-package.a$$FastClassBySpringCGLIB$$5f66283f.invoke() ~[spring-core-4.1.3.RELEASE.jar:na]
        在 org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) ~[spring-aop-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:267) ~[spring-tx-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) ~[spring-aop-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 my-package.a$$EnhancerBySpringCGLIB$$dfc04a57.b() ~[spring-core-4.1.3.RELEASE.jar:na]
        在 my-package.ab(c.java:165) ~[classes/:na]
        在 my-package.a$$FastClassBySpringCGLIB$$67dbe4b2.invoke() ~[spring-core-4.1.3.RELEASE.jar:na]
        在 org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717) ~[spring-aop-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) ~[spring-tx-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:267) ~[spring-tx-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653) ~[spring-aop-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 my-package.a$$EnhancerBySpringCGLIB$$d153236a.processApprovedApplications() ~[spring-core-4.1.3.RELEASE.jar:na]
        在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
        在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
        在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
        在 java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
        在 org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) ~[spring-context-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) ~[spring-context-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) [spring-context-4.1.3.RELEASE.jar:4.1.3.RELEASE]
        在 java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_121]
        在 java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_121]
        在 java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_121]
        在 java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_121]
        在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_121]
        在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_121]

har*_*ldK 5

这里的问题是ImageIO插件和容器(如 web/servlet 容器)的一个已知问题。将插件部署为 Web 应用程序的一部分不受ImageIO.

ImageIO 注册表用于跟踪注册的插件实际上是JVM全球(它实际上是每个应用程序上下文中的注册表,但通常只有一个单一的应用程序上下文*)。

  • 最安全的选择是在容器的“共享”或“公共”lib 文件夹中安装插件(及其所有依赖项)。这确保插件只安装一次,并且它们可用于所有容器的上下文。这需要控制容器环境,并且由于需要手动安装和完整的容器重启,升级起来也很麻烦。

  • 如果您更喜欢将插件部署为 Web 应用程序的一部分,我所知道的唯一选择是使用此处com.twelvemonkeys.servlet.image.IIOProviderContextListener所述的。

    Altenatively,在一个春天启动项目中使用它没有一个web.xml文件,你可以将下面的行添加到onStartup()方法在你SpringBootServletInitializer所描述的子类,在这里

    servletContext.addListener(IIOProviderContextListener.class);
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,您必须在第一次启用上下文侦听完全重新启动容器,因为它ImageIO可能已经从早期部署中“污染”了。

*) 不要与容器的 Web 应用程序上下文混淆,这可能有很多。


[怎么会] RawImageReaderSpiJVM 加载了一个类文件()却 RawImageInputStream没有加载?

链接中提到了这种情况,Web 应用程序的一个较早部署已RawImageReaderSpi在注册表中注册了该类,而该部署中的其余类由于重新部署已被删除。该RawImageInputStream提供新的部署,但随着新的Web应用程序上下文使用不同的ClassLoader情况下,原来的SPI类不能看到它,因为它是寻找同一类。