王玉平 發表於 2025-8-7 23:30:00

【分享排雷经历】系统引入Apache-Tika产生的NoClassDefFoundError错误

<p>今天,我们的重点工作是对<code>monorepo</code>系统的文件导入做安全控制,主要是通过判断文件的扩展名和类型,来限定用户导入文件的合法性,防止非法文件进入系统造成风险。</p>
<p>我们借用了此前在另一个系统<code>zfquan</code>基于<code>Apache Tika</code>的解决方案。</p>
<p>不巧,在运行main程序时,出现了一个 <code>NoClassDefFoundError</code> 错误-<strong>未找到<code>Apache Commons IO</code>(commons-io)类库的一个class的定义</strong>。</p>
<pre><code class="language-java">20:25:14.667 DEBUG org.apache.tika.config.TikaConfig - loading tika config from defaults; no config file specified
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/io/input/UnsynchronizedByteArrayInputStream
        at org.apache.tika.config.TikaConfig.getDefaultMimeTypes(TikaConfig.java:317)
        at org.apache.tika.config.TikaConfig.&lt;init&gt;(TikaConfig.java:246)
        at org.apache.tika.config.TikaConfig.getDefaultConfig(TikaConfig.java:390)
        at org.apache.tika.Tika.&lt;init&gt;(Tika.java:119)
        at com.emax.zhenghe.common.util.TikaFileSecurityUtils.&lt;init&gt;(TikaFileSecurityUtils.java:20)
        at com.emaxcard.car.TestMain.main(TestMain.java:38)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.io.input.UnsynchronizedByteArrayInputStream
        at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
        ... 6 more

Process finished with exit code 1
</code></pre>
<br>
<p>NoClassDefFoundError(而不是 ClassNotFoundException) 表示编译时类存在,但运行时找不到。</p>
<p>常见原因:</p>
<ul>
<li>
<p>依赖未正确引入。</p>
</li>
<li>
<p>依赖冲突导致类加载失败。</p>
</li>
<li>
<p>打包时遗漏了 commons-io.jar(如 maven-shade-plugin 未正确包含依赖)。</p>
</li>
</ul>
<hr>
<br>
<p>同样的Tika,为什么搬到<code>monorepo</code>就不行了呢?</p>
<p>经查maven依赖,<code>monorepo</code>系统与<code>zfquan</code>系统所依赖的 commons-io 的版本不同,<code>zfquan</code>是<strong>2.16.1</strong>,<code>monorepo</code>是<strong>2.6</strong>,这导致了问题的发生。</p>
<br>
<p>与单体结构的<code>zfquan</code>所不同的是,<code>monorepo</code>是一个庞大的同时拥有基础lib库和上层应用的工程。我们是在lib库的 sby-component-dfs 包 中添加的Tika依赖。</p>
<hr>
<p>我尝试在其中一个应用层pom里显式添加 <code>commons-io:2.16.1</code>,是可以解决问题的。</p>
<p>但,<code>monorepo</code>有多达数十个应用,我显然不能在这么多应用层里显式添加 <code>commons-io:2.16.1</code> 依赖。而且,这不符合我们的系统开发规范————maven包依赖统一在顶层pom来管理。</p>
<hr>
<p>那么,如何继续解决呢?</p>
<p>通过应用的maven依赖树(dependency:tree)得知,<code>commons-io:commons-io:jar:2.6</code> 是直接作为顶层依赖引入的(没有被其他库传递依赖)</p>
<p>然后我在IDE中全局查找 <code>&lt;artifactId&gt;commons-io&lt;/artifactId&gt;</code>,发现在顶层maven依赖管理文件 spring-base.pom 中,的确显式定义了 commons-io 的版本号!</p>
<pre><code class="language-xml">&lt;properties&gt;
    ...
        &lt;commons.version&gt;2.6&lt;/commons.version&gt;
&lt;/properties&gt;

&lt;dependencyManagement&gt;
    &lt;dependencies&gt;
      ...
      &lt;dependency&gt;
            &lt;groupId&gt;commons-io&lt;/groupId&gt;
            &lt;artifactId&gt;commons-io&lt;/artifactId&gt;
            &lt;version&gt;${commons.version}&lt;/version&gt;
      &lt;/dependency&gt;
    &lt;/dependencies&gt;
&lt;/dependencyManagement&gt;
</code></pre>
<p>如此,我把这个版本号变更为 2.16.1 ,也是可以解决问题的。</p>
<p>但,<code>monorepo</code>项目庞大,这样可能会拆东墙补西墙————可能影响其他用到commons-io的系统功能。</p>
<hr>
<p>so,我们得针对 Tika 版本来做文章,找到适配 <code>commons-io:2.6</code> 的版本。</p>
<p>DeepSeek很快给出答案:Tika 2.4.1依赖<code>commons-io:2.6</code>。开发者将 Tika 版本从 2.9.1 降级到 2.4.1,不再出现<code>NoClassDefFoundError</code>错误,并且经测试,这个版本的Tika可以满足我们对系统文件导入的安全控制。</p>


</div>
<div id="MySignature" role="contentinfo">
    <hr class="signhr"><p style="text-indent:2em;font-size:12px;text-align:center">当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge<br>本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/19027683</p><hr class="signhr">
<style>hr.signhr{width:80%;margin:0 auto;border: 0;height: 4px;background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0))}</style><br><br>
来源:https://www.cnblogs.com/buguge/p/19027683
頁: [1]
查看完整版本: 【分享排雷经历】系统引入Apache-Tika产生的NoClassDefFoundError错误