最近在打fat-jar包时,出现一个问题,运行fat-jar时报错:
2024-03-08 10:08:08.772 WARN [Thread-5] c.k.s.f.ExternalFuncClassLoader : 创建了未包含任何路径的自定义类加载器实例
2024-03-08 10:08:08.781 INFO [Thread-5] c.k.s.d.DataSourceConnectionPool : Calcite连接池初始化完成![连接池最大连接数:10,最大空闲数:5,最小空闲数:3,等待时间:PT3S]
java.sql.SQLException: No suitable driver found for jdbc:h2:file:C:\Users\yingxu.zhao\JsonQuery;MODE=MySQL;DB_CLOSE_DELAY=-1;AUTO_RECONNECT=TRUE;AUTO_SERVER=TRUE
at java.sql.DriverManager.getConnection(DriverManager.java:689)
at java.sql.DriverManager.getConnection(DriverManager.java:270)
at com.kanyun.sql.util.H2Utils.<clinit>(H2Utils.java:38)
at com.kanyun.sql.core.column.JsonTableColumnFactory.loadTableColumnInfo(JsonTableColumnFactory.java:124)
at com.kanyun.ui.JsonQuery.initConfig(JsonQuery.java:88)
at com.kanyun.ui.AsyncInitializer.run(AsyncInitializer.java:40)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "Thread-5" java.lang.RuntimeException: java.lang.NullPointerException
at com.kanyun.ui.AsyncInitializer.run(AsyncInitializer.java:61)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
at com.kanyun.sql.util.H2Utils.execQuery(H2Utils.java:47)
at com.kanyun.sql.core.column.JsonTableColumnFactory.loadTableColumnInfo(JsonTableColumnFactory.java:124)
at com.kanyun.ui.JsonQuery.initConfig(JsonQuery.java:88)
at com.kanyun.ui.AsyncInitializer.run(AsyncInitializer.java:40)
... 1 more
以上报错内容是使用maven-shade-plugin插件打包的,而换了maven-dependency-plugin打包也是同样的报错。
但是代码在IDEA中运行是没有问题的,报错提示的是找不到H2数据库驱动,查找打好包的fat-jar,里面是包含H2的驱动的。
这就很奇怪了,驱动明明在就是无法获取链接
然后找到一篇文章
java - No suitable driver found when exporting to a JAR-file? - Stack Overflow
里面的提问者,提到了他的应用里面同时使用了PostgreSQL和Mysql,由于数据库驱动使用了SPI机制,而打包时驱动的META-INF/services/java.sql.Driver并覆盖了,导致只能加载一个META-INF/services/java.sql.Driver。此时想到其实我的应用里面也有两个驱动 Calcite和H2。
然后就想到maven-shade-plugin是可以合并配置文件的。
找到以下文章:
使用Maven构建的可执行Jar无法在运行时解析多个数据库驱动程序的依赖关系 - IT屋-程序员软件开发技术分享社区
最终maven-shade-plugin配置如下:
<!--将项目的所有依赖项合并到单个可执行的JAR文件中,注意与maven-assembly-plugin插件的区别-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<!--原始jar名称:xx.jar,最终输出名称 true:xx-shaded.jar false:xx.jar并修改原始名称为original-xx.jar-->
<shadedArtifactAttached>true</shadedArtifactAttached>
<!--生成名为dependency-reduced-pom.xml,这个POM文件去掉了原始pom中已被包含的进fat-jar的依赖项-->
<createDependencyReducedPom>true</createDependencyReducedPom>
<!-- 解决插件打包后运行报错:Exception in thread "main" java.lang.SecurityException: Invalid signature file digest for Manifest main attributes-->
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<!--自动移除项目中没有使用到的依赖,以此来最小化 jar 包的体积-->
<!--<minimizeJar>true</minimizeJar>-->
<transformers>
<!-- 添加入口类 -->
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<!-- 入口类 -->
<Main-Class>${main-class}</Main-Class>
</manifestEntries>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<!-- 合并服务,多个数据库驱动并存的情况不合并的话,H2驱动会报错(No suitable driver found for jdbc:h2:file)因为程序包含两个数据库驱动,Calcite和H2 -->
<resource>META-INF/services/java.sql.Driver</resource>
</transformer>
</transformers>
<artifactSet>
<!--默认所有的依赖都会被解压并平铺到最终的fat-jar中,这里指定要排除的依赖-->
<excludes>
<!--<exclude>*:hutool-all</exclude>-->
</excludes>
</artifactSet>
</configuration>
</plugin>