Я рассмотрел очень специфическую проблему, решение которой кажется чем-то простым:
Моя (Spring) иерархия загрузчиков классов приложений выглядит примерно так: SystemClassLoader -> PlatformClassLoader -> AppClassLoader
Если я использую Java CompleteableFuture
для запуска потоков. ContextClassLoader
потоков: SystemClassLoader -> PlatformClassLoader -> ThreadClassLoader
Таким образом, я не могу получить доступ ни к одному классу в AppClassLoader
, хотя должен, потому что там находятся все классы внешних библиотек.
Исходная база достаточно велика, поэтому я не хочу/не могу переписать все части, связанные с потоками, во что-то другое (например, передавать собственного исполнителя каждому вызову).
Итак, мой вопрос: Как я могу создавать темы, созданные, например, CompleteableFuture.supplyAsync()
использовать AppClassLoader
в качестве родителя? (вместо PlatformClassloader
)
Я обнаружил, что ForkJoinPool используется для создания потоков. Но, как мне кажется, все там статично и окончательно. Поэтому я сомневаюсь, что даже установка пользовательского ForkJoinWorkerThreadFactory с системным свойством поможет в этом случае. Или это будет?
Изменить, чтобы ответить на вопросы из комментариев:
где вы развертываете? Это работает в Jetty/Tomcat/любом контейнере JEE?
- Я использую настройку Spring Boot по умолчанию, поэтому используется внутренний контейнер Tomcat.
Какая именно у вас проблема?
- Точная проблема: java.lang.IllegalArgumentException: org.keycloak.admin.client.resource.RealmsResource, на который ссылается метод, не виден в загрузчике классов
Задания, которые вы отправляете в supplyAsync(), создаются из AppClassLoader, не так ли?
supplyAsync
вызывается изMainThread
, который используетAppClassLoader
. Но отладка приложений показывает, что все такие потоки имеютPlatformClassLoader
в качестве родителя. Насколько я понимаю, это происходит потому, что ForkJoinPool.commonPool() создается во время запуска приложения (потому что оно статическое) и поэтому использует загрузчик класса по умолчанию в качестве родителя, который являетсяPlatformClassLoader
. Таким образом, все потоки из этого пула получаютPlatformClassLoader
в качестве родителя для ContextClassLoader (вместо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]