Quarkus原生镜像模式下AgroalDataSource连ClickHouse遇SQLException
问题:Quarkus原生镜像运行ClickHouse连接时出现SQLException错误
错误日志
redis-client, resteasy, resteasy-jackson, smallrye-context-propagation, smallrye-health, smallrye-reactive-messaging, smallrye-reactive-messaging-kafka, vertx] 23:46:46 WARN traceId=, parentId=, spanId=, sampled= [io.ag.pool] (agroal-11) Datasource '<default>': Failed to get service com.clickhouse.client.ClickHouseSslContextProvider, server ClickHouseNode [uri=https hidden url]@-1477137086 java.sql.SQLException: Failed to get service com.clickhouse.client.ClickHouseSslContextProvider, server ClickHouseNode [uri=https hidden url]@-1477137086 at com.clickhouse.jdbc.SqlExceptionUtils.handle(SqlExceptionUtils.java:85) at com.clickhouse.jdbc.SqlExceptionUtils.create(SqlExceptionUtils.java:31) at com.clickhouse.jdbc.SqlExceptionUtils.handle(SqlExceptionUtils.java:90) at com.clickhouse.jdbc.internal.ClickHouseConnectionImpl.getServerInfo(ClickHouseConnectionImpl.java:93) at com.clickhouse.jdbc.internal.ClickHouseConnectionImpl.<init>(ClickHouseConnectionImpl.java:298) at com.clickhouse.jdbc.internal.ClickHouseConnectionImpl.<init>(ClickHouseConnectionImpl.java:241) at com.clickhouse.jdbc.ClickHouseDriver.connect(ClickHouseDriver.java:145) at com.clickhouse.jdbc.ClickHouseDriver.connect(ClickHouseDriver.java:41) at io.agroal.pool.ConnectionFactory.createConnection(ConnectionFactory.java:226) at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:536) at io.agroal.pool.ConnectionPool$CreateConnectionTask.call(ConnectionPool.java:517) at java.base@17.0.8/java.util.concurrent.FutureTask.run(FutureTask.java:264) at io.agroal.pool.util.PriorityScheduledExecutor.beforeExecute(PriorityScheduledExecutor.java:75) at java.base@17.0.8/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134) at java.base@17.0.8/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base@17.0.8/java.lang.Thread.run(Thread.java:833) at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:775) at org.graalvm.nativeimage.builder/com.oracle.svm.core.windows.WindowsPlatformThreads.osThreadStartRoutine(WindowsPlatformThreads.java:178)
相关代码片段
import io.agroal.api.AgroalDataSource; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @Path("") public class ExampleRessource { @Inject AgroalDataSource dataSource; @GET @Produces(MediaType.TEXT_PLAIN) public String getTime() { String toReturn=null; try (Connection con = dataSource.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT name FROM system.databases")) { try (ResultSet rs = ps.executeQuery();) { rs.next(); toReturn = "Current time: " + rs.getString(1); System.out.println(toReturn); } } catch (SQLException e) { e.printStackTrace(); } return toReturn; } }
POM配置
<properties> <maven.compiler.release>17</maven.compiler.release> <compiler-plugin.version>3.11.0</compiler-plugin.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id> <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id> <quarkus.platform.version>3.2.2.Final</quarkus.platform.version> <jdbc.clickhouse.version>3.0.1</jdbc.clickhouse.version> <surefire-plugin.version>3.0.0-M7</surefire-plugin.version> <clickhouse.jdbc.version>0.4.1</clickhouse.jdbc.version> </properties> <dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-arc</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-config-yaml</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-jackson</artifactId> </dependency> <dependency> <groupId>io.quarkiverse.jdbc</groupId> <artifactId>quarkus-jdbc-clickhouse</artifactId> <version>${jdbc.clickhouse.version}</version> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-agroal</artifactId> </dependency> <dependency> <groupId>com.clickhouse</groupId> <artifactId>clickhouse-jdbc</artifactId> <classifier>http</classifier> <version>${clickhouse.jdbc.version}</version> <scope>test</scope> <exclusions> <exclusion> <groupId>*</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>${quarkus.platform.group-id}</groupId> <artifactId>${quarkus.platform.artifact-id}</artifactId> <version>${quarkus.platform.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
已尝试操作
- 应用正常启动运行无问题
- 原生镜像可正常生成
- 仅运行原生镜像时出现错误
补充信息
- 使用GraalVM 22.3.0构建原生镜像
- 尝试过新版本GraalVM和Quarkus,问题依旧
- 通过URL添加
?ssl=true以HTTPS方式访问ClickHouse
解决方案
错误根源是GraalVM原生镜像静态分析时,无法自动发现ClickHouse的SSL上下文提供者(com.clickhouse.client.ClickHouseSslContextProvider),该类通过ServiceLoader动态加载,默认不会被包含进原生镜像。
1. 调整依赖范围
将clickhouse-jdbc的test scope改为compile,确保生产环境能获取到SSL相关实现:
<dependency> <groupId>com.clickhouse</groupId> <artifactId>clickhouse-jdbc</artifactId> <classifier>http</classifier> <version>${clickhouse.jdbc.version}</version> <exclusions> <exclusion> <groupId>*</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency>
2. 注册反射类
使用Quarkus的@RegisterForReflection注解,在项目中添加一个配置类,将SSL上下文提供者注册到反射列表:
import io.quarkus.runtime.annotations.RegisterForReflection; @RegisterForReflection(targets = com.clickhouse.client.core.DefaultClickHouseSslContextProvider.class) public class NativeImageReflectionConfig {}
或者通过配置文件方式,创建src/main/resources/META-INF/native-image/reflect-config.json:
[ { "name": "com.clickhouse.client.core.DefaultClickHouseSslContextProvider", "allDeclaredConstructors": true, "allPublicConstructors": true, "allDeclaredMethods": true, "allPublicMethods": true } ]
3. 完善JDBC URL配置
如果是测试环境,可添加sslmode=none跳过证书验证;生产环境需配置合法证书:
quarkus.datasource.jdbc.url=jdbc:clickhouse://your-host:8443/default?ssl=true&sslmode=none
4. 重新构建原生镜像
执行命令重新构建并运行:
./mvnw clean package -Dnative ./target/your-app-name-1.0.0-SNAPSHOT-runner
内容的提问来源于stack exchange,提问作者fares ben
相关产品推荐
相关产品推荐

