升级Hibernate 5后exec-maven-plugin执行Java主类时进程挂起
问题根源与解决方案
你遇到的问题确实是Hibernate 5的行为变更导致的——Hibernate 5.x要求显式关闭StandardServiceRegistry,否则底层服务的后台线程会持续存活,导致JVM进程无法正常退出,这就是exec-maven-plugin挂起、无法进入后续Maven阶段的核心原因。
在Hibernate 4.x中,相关资源的清理逻辑是自动处理的,但5.x重构了服务注册机制,StandardServiceRegistry持有连接池、事务管理器等核心服务的引用,如果不主动销毁,这些服务的后台线程会阻止JVM退出,进而让exec-maven-plugin的进程一直挂着无法返回。
修复步骤
你需要修改代码,显式创建并销毁StandardServiceRegistry,具体调整如下:
// 1. 显式创建并保存StandardServiceRegistry实例 StandardServiceRegistry registry = new StandardServiceRegistryBuilder() .applySetting("hibernate.hbm2ddl.auto", "create") .applySetting("hibernate.connection.driver_class", dialect.getDriver()) .applySetting("hibernate.dialect", dialect.getDialectClass()) .applySetting("hibernate.connection.url", "jdbc:mysql://" + host + ":" + port + "/" + databaseName) .applySetting("hibernate.connection.username", username) .applySetting("hibernate.connection.password", password) .build(); try { // 2. 基于registry创建MetadataSources MetadataSources metadata = new MetadataSources(registry); // 若需加载实体类,可补充:metadata.addAnnotatedClass(YourEntity.class); 或 metadata.addPackage("com.your.entity.package"); // 3. 执行SchemaExport操作 SchemaExport export = new SchemaExport(); export.setDelimiter(";"); export.setOutputFile(directory + File.separator + outputFile); export.setFormat(true); export.execute(EnumSet.of(TargetType.SCRIPT), SchemaExport.Action.CREATE, metadata.buildMetadata()); } finally { // 4. 关键:在finally块中销毁registry,释放所有底层资源 StandardServiceRegistryBuilder.destroy(registry); }
为什么之前的方案无效?
<async>true:仅让Maven异步执行插件,但核心问题是JVM进程本身无法退出,异步配置无法解决线程存活的根本问题。System.exit(0):直接终止了整个Maven进程,自然无法继续后续的单元测试等阶段。- bash脚本异步:大概率是脚本执行时的环境变量、类路径配置有误,导致Java程序未正确生成脚本,且这种方式并非优雅的解决方案。
额外注意事项
- 如果你的实体类是通过包扫描加载的,确保
MetadataSources正确加载了所有映射(比如使用metadata.addPackage("com.your.entity.package"))。 - 检查是否有其他自定义资源(如手动创建的JDBC连接)未关闭,但核心问题还是
StandardServiceRegistry的销毁。
内容的提问来源于stack exchange,提问作者King Midas
相关产品推荐
相关产品推荐

