CompletableFuture / ForkJoinPool Set Class Loader
我解决了一个非常具体的问题,其解决方案似乎是基本的东西:
我的(Spring)应用程序的类装入器层次结构是这样的:SystemClassLoader -> PlatformClassLoader -> AppClassLoader
如果我使用Java来运行线程。线程的值为:CompleteableFuture
ContextClassLoader
SystemClassLoader -> PlatformClassLoader -> ThreadClassLoader
因此,尽管我必须访问中的任何类,因为我必须这样做,因为所有外部库类都驻留在其中。AppClassLoader
源代码库非常大,所以我不想/不能将所有与线程相关的部分重写为其他东西(例如,为每个调用传递一个自定义执行器)。
所以我的问题是:如何使例如ComputerableFuture.supplyAsync()
创建的线程使用AppClassLoader
作为父级?PlatformClassloader
)
我发现ForkJoinPool用于创建线程。但在我看来,那里的一切都是静态的和最终的。因此,我怀疑在这种情况下,即使使用系统属性设置自定义ForkJoinWorkerThreadFactory也会有所帮助。还是会?
编辑以回答评论中的问题:
-
部署到哪里?这是在码头/雄猫/任何JEE容器内运行的吗?
- 我使用的是默认的Spring Boot设置,因此使用了内部tomcat容器。
-
您遇到的确切问题是什么?
- 确切的问题是:java.lang.IllegalArgumentException: org.keycloak.admin.client.resource.Realms从方法引用的资源在类装入器中不可见
-
您提交给 supplyAsync() 的作业是从 AppClassLoader 创建的,不是吗?
从 调用,它使用 .但是,调试应用程序表明,所有这些线程都作为其父线程。至于我的理解,发生这种情况是因为ForkJoinPool.commonPool()是在应用程序启动期间构造的(因为它是静态的),因此使用默认类装入器作为父级,即.因此,此池中的所有线程都作为 ContextClassLoader 的父线程(而不是 )。
supplyAsync
MainThread
AppClassLoader
PlatformClassLoader
PlatformClassLoader
PlatformClassLoader
AppClassLoader
当我在内部创建自己的执行器并将此执行器传递给一切工作时 - 我可以在调试期间看到现在确实是我的父级。这似乎证实了我在第一种情况下的假设,即公共池不是由至少不是在使用自身时创建的。
MainThread
supplyAsync
AppClassLoader
ThreadClassLoader
MainThread
AppClassLoader
全栈跟踪:
java.lang.IllegalArgumentException: org.keycloak.admin.client.resource.RealmsResource referenced from a method is not visible from class loader
at java.base/java.lang.reflect.Proxy$ProxyBuilder.ensureVisible(Proxy.java:851) ~[na:na]
at java.base/java.lang.reflect.Proxy$ProxyBuilder.validateProxyInterfaces(Proxy.java:682) ~[na:na]
at java.base/java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:628) ~[na:na]
at java.base/java.lang.reflect.Proxy.lambda$getProxyConstructor$1(Proxy.java:426) ~[na:na]
at java.base/jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:327) ~[na:na]
at java.base/jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:203) ~[na:na]
at java.base/java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:424) ~[na:na]
at java.base/java.lang.reflect.Proxy.newProxyInstance(Proxy.java:999) ~[na:na]
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.proxy(ProxyBuilder.java:79) ~[resteasy-client-3.1.4.Final.jar!/:3.1.4.Final]
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.build(ProxyBuilder.java:131) ~[resteasy-client-3.1.4.Final.jar!/:3.1.4.Final]
at org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.proxy(ClientWebTarget.java:93) ~[resteasy-client-3.1.4.Final.jar!/:3.1.4.Final]
at org.keycloak.admin.client.Keycloak.realms(Keycloak.java:114) ~[keycloak-admin-client-3.4.3.Final.jar!/:3.4.3.Final]
at org.keycloak.admin.client.Keycloak.realm(Keycloak.java:118) ~[keycloak-admin-client-3.4.3.Final.jar!/:3.4.3.Final]