You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

命令行运行jar包报Hibernate Search SearchFactory未初始化异常

问题背景

使用Hibernate Search 5.9.3版本时,在Eclipse中运行代码可正常执行、索引创建流程无报错,但通过命令行运行打包生成的jar文件时抛出异常,异常截图如下:
异常截图
涉及的代码片段:

factory = configuration.buildSessionFactory(serviceRegistry);
Session session = factory.openSession();
try {
    Thread.sleep(10);
} catch (InterruptedException e1) {
    e1.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
    @Override
    public void run() {
        System.out.println("1:Search.getFullTextEntityManager(factory.openSession())");
        fullTextEntityManager = Search.getFullTextEntityManager(session);
        session.getTransaction().begin();
        try {
            Thread.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("2:fullTextEntityManager.createIndexer().startAndWait();");
        try {
            fullTextEntityManager.createIndexer().startAndWait();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } catch (Exception ex) {
            System.out.println("3:fullTextEntityManager.createIndexer().startAndWait();");
            try {
                fullTextEntityManager.createIndexer().startAndWait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ex.printStackTrace();
        }
        try {
            session.getTransaction().commit();
        } catch (Exception e) {
            session.getTransaction().rollback();
        } 
    }
});
核心原因

Eclipse运行项目时会自动将所有关联依赖加入运行时类路径,因此不会出现类找不到、服务加载失败的问题。但默认打包生成的jar仅包含项目自身的编译文件,不会引入Hibernate Search、Lucene等传递依赖,同时如果打包时未处理Java SPI配置文件,也会导致Hibernate Search无法加载内置组件,命令行运行时就会抛出异常。
另外现有代码存在线程使用隐患:在Swing事件调度线程(EDT)中执行startAndWait()这类阻塞式重IO操作,会直接导致UI卡顿,只是Eclipse环境下依赖齐全未触发类加载错误,该问题才没有显现。

排查思路
  • 先查看命令行抛出的完整异常栈,如果是ClassNotFoundException、NoClassDefFoundError或者服务加载相关报错,可直接定位为类路径缺失/打包配置错误
  • 解压打包生成的jar,检查内部是否包含Hibernate Search、Lucene、Hibernate Core相关的class文件,以及META-INF/services目录下是否存在Hibernate Search对应的SPI配置文件
  • 确认命令行运行时是否通过-cp参数完整指定了所有依赖包的路径,没有遗漏必要依赖
解决方案

方案1:打包时将所有依赖合并入可执行jar

如果使用Maven构建,推荐使用maven-shade-plugin打包,它会自动处理SPI配置文件的合并,避免服务加载失败,在pom.xml中添加如下配置:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.4.1</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>替换为你的主类全限定名</mainClass>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

配置完成后执行mvn package,生成的jar包可直接通过java -jar 包名.jar运行。
如果使用Gradle构建,在build.gradle中添加如下配置:

plugins {
    id 'java'
}
jar {
    manifest {
        attributes 'Main-Class': '替换为你的主类全限定名'
    }
    from {
        configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
    }
    // 合并SPI配置文件,排除签名文件避免报错
    exclude 'META-INF/*.SF'
    exclude 'META-INF/*.DSA'
    exclude 'META-INF/*.RSA'
    mergeServiceFiles()
}

方案2:运行时手动指定依赖类路径

如果不需要将所有依赖打入单个jar,可以把所有依赖包统一放在lib目录下,运行时通过-cp参数指定类路径:
Windows环境执行命令:

java -cp "你的项目jar包.jar;lib/*" 你的主类全限定名

Linux/macOS环境执行命令:

java -cp "你的项目jar包.jar:lib/*" 你的主类全限定名

代码优化建议

将索引构建逻辑从Swing EDT线程移到独立工作线程,避免UI阻塞,同时不要跨线程共享Session实例:

new Thread(() -> {
    // 工作线程单独打开Session和事务
    FullTextEntityManager ftem = Search.getFullTextEntityManager(factory.openSession());
    ftem.getTransaction().begin();
    try {
        ftem.createIndexer().startAndWait();
        ftem.getTransaction().commit();
    } catch (Exception e) {
        if (ftem.getTransaction().isActive()) {
            ftem.getTransaction().rollback();
        }
        e.printStackTrace();
    } finally {
        ftem.close();
    }
    // 索引构建完成后再切回EDT线程更新UI
    SwingUtilities.invokeLater(() -> {
        // 填写索引完成后的UI刷新逻辑
    });
}).start();

内容的提问来源于stack exchange,提问作者svkvvenky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 15:48:16