我有一个 Java 类,它由第三方应用程序实例化为扩展。也就是说,根据第 3 方软件设计,像我们这样的客户将我们的 Java 类注册到他们的应用程序中,他们的应用程序将安装它以在正确的位置和时间执行自定义逻辑。
我们的自定义 Java 类需要编码和解码 XML,为此它使用 JAXB。因此它需要一个 JAXB 上下文。
我天真地调用了JAXBContext.newInstance(MyClass.class)
每次调用时,很快就会发现这是众所周知的内存泄漏原因。常见的做法是创建一个(或最多几个)JAXB 上下文以在整个应用程序之间共享。
很好,除了调用我的类的第三方应用程序在该调用私有(private)的新 ClassLoader 实例上进行每次调用。
所以,即使我输入 JAXBContext
在 static
字段或 static HashMap<>
,它对于调用来说仍然是私有(private)的!
问题
如何在从私有(private) ClassLoader 实例实例化的类中创建一个在 JVM 中共享的单例?
我正在考虑两种可能的思路,但我想了解如何使它们发挥作用或任何人拥有的任何完全不同的方法的建议。
我的三个想法是:
在 JVM 类中找到可以编写对象的位置。例如,如果
System.setProperty
可以写Object
的实例而不仅仅是String
,想法是创建 JAXB 上下文并将其放入属性中,因为可以肯定System
已经被实例化并且自定义类加载器实例将继承它。但是System.setProperty
不占用Object
值,所以我不知道执行此操作的实用方法。以某种方式强制将类加载到我可以通过 JAXB 上下文存储的父类或根类加载器上。我不知道该怎么做。
使用 ThreadLocal 来存储 JAXBContext。我不认为每次调用都是一个全新的线程(它们可能从线程池中重用),所以这可能是限制我的上下文的方法。但是如何创建 ThreadLocal 变量以便在实例之间共享呢?看来这给我带来了同样的问题。
最佳答案
听起来您的代码已在 3rd 方应用程序中沙箱化。因此,使用static
或ThreadLocal
不会有帮助,因为它只会存在于同一个classloader
中,并且如果该classloader
> 被改变...然后上下文就丢失了。
最接近的解决方案是将您的上下文注入(inject)到应用程序代码中。这不是最好的主意,因为它可能会受到外界的影响并产生意想不到的后果。请注意,这意味着您在类加载器中创建的值将保留在应用程序中,因此创建的类加载器永远不会被垃圾收集。还有一个问题是 JAXB
jar 来自哪里。我从你的代码而不是第三方假设。因此,每次都会在不同的类加载器中加载该 jar,因此从那里共享对象可能会出现问题并且需要一些代理。
老实说,可能会有很多不可预见的结果。
最好的想法是要求第 3 方为您提供一些 API 来实现这一点。
在继续之前,让我们看看其他选项:
- 是否可以替代使用
JAXB
?不会出现相同的内存泄漏问题的东西。 - 内存泄漏有严重吗?如果在第 3 方应用程序提供 API 之前出现临时内存泄漏怎么办?
如果您确实想尝试注入(inject)该对象,我很乐意提供帮助。但是,根据经验,这类事情很困惑。
关于java - 如何从私有(private)类加载器中创建单例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61787736/