Quarkus 无法加载 cassandra 自定义重试策略 class

Quarkus unable to load the cassandra custom retry policy class

我正在执行将 Quarkus 从 1.x 迁移到 2.x 的任务,而 Quarkus 与嵌入式 Cassandra 的集成在单元测试中失败并出现错误 -

原因:java.lang.IllegalArgumentException:找不到 class com.mind.common.connectors.cassandra.CassandraCustomRetryPolicy (由 advanced.retry-policy.class 指定)

                    **Custom retry policy**

public class CassandraCustomRetryPolicy implements RetryPolicy {

    public CassandraCustomRetryPolicy(DriverContext context, String profileName) {
    }
 //override methods
}

               ****quarkus test be like** -**

@QuarkusTest
@QuarkusTestResource(CassandraTestResource.class)
class Test {}


       **CassandraTestResource class start the embedded cassandra** 



 public class CassandraTestResource implements QuarkusTestResourceLifecycleManager {
    
        private Cassandra cassandra;
    
        @Override
        public Map<String, String> start() {
            cassandra = new CassandraBuilder().version("3.11.9")
                    .addEnvironmentVariable("JAVA_HOME", getJavaHome())
                    .addJvmOptions("-Xms512M -Xmx512m").build();
    
            cassandra.start();
    }

我已经覆盖了资源文件夹内 application.conf 中的默认 Cassandra 驱动程序策略。

  datastax-java-driver {
          basic.request {
            timeout = ****
            consistency = ***
            serial-consistency = ***
          }
          advanced.retry-policy {
            class = com.mind.common.connectors.cassandra.CassandraCustomRetryPolicy
          }

我发现我的自定义重试策略 class 在 QuarkusClassLoader.java-

中属于禁止资源
String resourceName = sanitizeName(name).replace('.', '/') + ".class";
                boolean parentFirst = parentFirst(resourceName, state);
                if (state.bannedResources.contains(resourceName)) {
                    throw new ClassNotFoundException(name);
                }

我捕获了以下日志 -

java.lang.ClassNotFoundException: com.mind.common.connectors.cassandra.CassandraCustomRetryPolicy 在 io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:438) 在 io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:414) 在 java.base/java.lang.Class.forName0(本机方法) 在 java.base/java.lang.Class.forName(Class.java:315) 在 com.datastax.oss.driver.internal.core.util.Reflection.loadClass(Reflection.java:57) 在 com.datastax.oss.driver.internal.core.util.Reflection.resolveClass(Reflection.java:288) 在 com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfig(Reflection.java:235) 在 com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfig 配置文件(Reflection.java:194) 在 com.datastax.oss.driver.internal.core.context.DefaultDriverContext.buildRetryPolicies(DefaultDriverContext.java:359) 在 com.datastax.oss.driver.internal.core.util.concurrent.LazyReference.get(LazyReference.java:55) 在 com.datastax.oss.driver.internal.core.context.DefaultDriverContext.getRetryPolicies(DefaultDriverContext.java:761) 在 com.datastax.oss.driver.internal.core.session.DefaultSession$SingleThreaded.init(DefaultSession.java:339) 在 com.datastax.oss.driver.internal.core.session.DefaultSession$SingleThreaded.access$1100(DefaultSession.java:300) 在 com.datastax.oss.driver.internal.core.session.DefaultSession.lambda$init$0(DefaultSession.java:146) 在 io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98) 在 io.netty.util.concurrent.PromiseTask.run(PromiseTask.java:106) 在 io.netty.channel.DefaultEventLoop.run(DefaultEventLoop.java:54) 在 io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986) 在 io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) 在 io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) 在 java.base/java.lang.Thread.run(Thread.java:834)

我正在使用 quarkus 版本 2.7。2.Final 和 cassandra 驱动程序版本 4.14.0

这不是一个完整的答案,但我想在这里留下一些注释,以防其他人在我回到它之前完成它。

这里的根本问题是,在上述 Quarkus 测试用例中,Java 驱动程序代码由 QuarkusClassLoader 加载,其中 (a) 对从何处加载代码有更多限制,(b) 没有'如有必要,似乎不会立即支持调用它的父级。因此在这种情况下,在测试中执行以下操作将失败并出现 ClassNotFoundException:

CqlSession.class.getClassLoader().forName(customretrypolicyclassname)

而以下操作没有问题:

CqlSession.class.getClassLoader().getParent().forName(customretrypolicyclassname)

用于加载 CqlSession 的 class 加载器是 QuarkusClassLoader 实例,而它的父级是普通 JVM class 加载器。

Java 驱动程序 uses Class.forName() 加载为此策略指定的 classes。但是由于 Quarkus class 加载器用于加载驱动程序代码本身,它是用于这些反射操作的加载器......并且如上所述,该驱动程序具有一些使加载外部代码更难的特定特征。

在我像 -

一样初始化 CQL 会话后它起作用了

CqlSession.builder() .addContactPoint(new InetSocketAddress(settings.getAddress(), settings.getPort())) .withLocalDatacenter("***") . withClassLoader(Thread.currentThread().getContextClassLoader()).build())