- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我解决了一个非常具体的问题,其解决方案似乎是基本的:
我的 (Spring) 应用程序的类加载器层次结构是这样的:SystemClassLoader -> PlatformClassLoader -> AppClassLoader
如果我使用 Java CompleteableFuture
来运行线程。线程的ContextClassLoader
为:SystemClassLoader -> PlatformClassLoader -> ThreadClassLoader
因此,我无法访问 AppClassLoader
中的任何类,尽管我必须这样做,因为所有外部库类都驻留在那里。
源代码库非常大,所以我不想/不能将所有与线程相关的部分重写为其他内容(例如,将自定义执行程序传递给每个调用)。
所以我的问题是:我怎样才能使创建的线程例如CompleteableFuture.supplyAsync()
使用 AppClassLoader
作为父级?(而不是 PlatformClassloader
)
我发现 ForkJoinPool用于创建线程。但在我看来,一切都是static和final。所以我怀疑即使设置自定义 ForkJoinWorkerThreadFactory在这种情况下,使用系统属性会有所帮助。还是会?
编辑以回答评论中的问题:
你在哪里部署?这是否在 jetty/tomcat/任何 JEE 容器中运行?
您遇到的具体问题是什么?
您提交给 supplyAsync() 的作业是从 AppClassLoader 创建的,不是吗?
supplyAsync
是从使用 AppClassLoader
的 MainThread
调用的。但是,调试应用程序显示所有此类线程都将 PlatformClassLoader
作为其父级。据我了解,这是因为 ForkJoinPool.commonPool()在应用程序启动期间构建(因为它是静态的),因此使用默认的类加载器作为父类,即 PlatformClassLoader
。因此,该池中的所有线程都将 PlatformClassLoader
作为 ContextClassLoader 的父级。 (而不是 AppClassLoader
)。
当我在 MainThread
中创建自己的执行程序并将此执行程序传递给 supplyAsync
时,一切正常 - 在调试过程中我可以看到现在确实 AppClassLoader
是我的 ThreadClassLoader
的父级。这似乎证实了我在第一种情况下的假设,即公共(public)池不是由 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]
最佳答案
我遇到了类似的事情,想出了一个不使用反射的解决方案,似乎与 JDK9-JDK11 配合得很好。
这里是javadocs说:
The parameters used to construct the common pool may be controlled by setting the following system properties:
- java.util.concurrent.ForkJoinPool.common.threadFactory - the class name of a ForkJoinPool.ForkJoinWorkerThreadFactory. The system class loader is used to load this class.
因此,如果您推出自己的 ForkJoinWorkerThreadFactory
版本并将其设置为使用系统属性使用正确的 ClassLoader
,这应该可以工作。
这是我的自定义 ForkJoinWorkerThreadFactory
:
package foo;
public class MyForkJoinWorkerThreadFactory implements ForkJoinWorkerThreadFactory {
@Override
public final ForkJoinWorkerThread newThread(ForkJoinPool pool) {
return new MyForkJoinWorkerThread(pool);
}
private static class MyForkJoinWorkerThread extends ForkJoinWorkerThread {
private MyForkJoinWorkerThread(final ForkJoinPool pool) {
super(pool);
// set the correct classloader here
setContextClassLoader(Thread.currentThread().getContextClassLoader());
}
}
}
然后在你的应用启动脚本中设置系统属性
-Djava.util.concurrent.ForkJoinPool.common.threadFactory=foo.MyForkJoinWorkerThreadFactory
上述解决方案的工作原理是,当第一次引用 ForkJoinPool 类并初始化 commonPool
时,此线程的上下文 ClassLoader 是您需要的正确的(而不是 System类加载器)。
这里有一些 background这可能会有所帮助:
Fork/Join common pool threads return the system class loader as their thread context class loader.
In Java SE 9, threads that are part of the fork/join common pool will always return the system class loader as their thread context class loader. In previous releases, the thread context class loader may have been inherited from whatever thread causes the creation of the fork/join common pool thread, e.g. by submitting a task. An application cannot reliably depend on when, or how, threads are created by the fork/join common pool, and as such cannot reliably depend on a custom defined class loader to be set as the thread context class loader.
由于上述向后不兼容的变化,使用以前在JDK8中工作的ForkJoinPool
的东西在JDK9+中可能无法工作。
关于java - CompletableFuture/ForkJoinPool 集合类加载器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49113207/
我之前让 dll 注入(inject)器变得简单,但我有 Windows 7,我用 C# 和 C++ 做了它,它工作得很好!但是现在当我在 Windows 8 中尝试相同的代码时,它似乎没有以正确的方
我正在尝试制作一个名为 core-splitter 的元素,该元素在 1.0 中已弃用,因为它在我们的项目中起着关键作用。 如果您不知道 core-splitter 的作用,我可以提供一个简短的描述。
我有几个不同的蜘蛛,想一次运行所有它们。基于 this和 this ,我可以在同一个进程中运行多个蜘蛛。但是,我不知道如何设计一个信号系统来在所有蜘蛛都完成后停止 react 器。 我试过了: cra
有没有办法在达到特定条件时停止扭曲 react 器。例如,如果一个变量被设置为某个值,那么 react 器应该停止吗? 最佳答案 理想情况下,您不会将变量设置为一个值并停止 react 器,而是调用
https://code.angularjs.org/1.0.0rc9/angular-1.0.0rc9.js 上面的链接定义了外部js文件,我不知道Angular-1.0.0rc9.js的注入(in
我正在尝试运行一个函数并将服务注入(inject)其中。我认为这可以使用 $injector 轻松完成.所以我尝试了以下(简化示例): angular.injector().invoke( [ "$q
在 google Guice 中,我可以使用函数 createInjector 创建基于多个模块的注入(inject)器。 因为我使用 GWT.create 在 GoogleGin 中实例化注入(in
我在 ASP.NET Core 1.1 解决方案中使用配置绑定(bind)。基本上,我在“ConfigureServices Startup”部分中有一些用于绑定(bind)的简单代码,如下所示: s
我在 Spring MVC 中设置 initBinder 时遇到一些问题。我有一个 ModelAttribute,它有一个有时会显示的字段。 public class Model { privat
我正在尝试通过jquery post发布knockoutjs View 模型 var $form = $('#barcodeTemplate form'); var data = ko.toJS(vm
如何为包含多态对象集合的复杂模型编写自定义模型绑定(bind)程序? 我有下一个模型结构: public class CustomAttributeValueViewModel { publi
您好,我正在尝试实现我在 this article 中找到的扩展方法对于简单的注入(inject)器,因为它不支持开箱即用的特定构造函数的注册。 根据这篇文章,我需要用一个假的委托(delegate)
你好,我想自动注册我的依赖项。 我现在拥有的是: public interface IRepository where T : class public interface IFolderReposi
我正在使用 Jasmine 测试一些 Angular.js 代码。为此,我需要一个 Angular 注入(inject)器: var injector = angular.injector(['ng'
我正在使用 Matlab 代码生成器。不可能包含代码风格指南。这就是为什么我正在寻找一个工具来“ reshape ”、重命名和重新格式化生成的代码,根据我的: 功能横幅约定 文件横幅约定 命名约定 等
这个问题在这里已经有了答案: Where and why do I have to put the "template" and "typename" keywords? (8 个答案) 关闭 8
我开发了一种工具,可以更改某些程序的外观。为此,我需要在某些进程中注入(inject)一个 dll。 现在我基本上使用这个 approach .问题通常是人们无法注入(inject) dll,因为他们
我想使用 swing、spring 和 hibernate 编写一个 java 应用程序。 我想使用数据绑定(bind)器用 bean 的值填充 gui,并且我还希望它反射(reflect) gui
我有这段代码,当两个蜘蛛完成后,程序仍在运行。 #!C:\Python27\python.exe from twisted.internet import reactor from scrapy.cr
要点是 Spring Batch (v2) 测试框架具有带有 @Autowired 注释的 JobLauncherTestUtils.setJob。我们的测试套件有多个 Job 类提供者。因为这个类不
我是一名优秀的程序员,十分优秀!