我有一个Java类,该类由第三方应用程序实例化为扩展。也就是说,根据第三方软件设计,像我们这样的客户将Java类注册到他们的应用程序,他们的应用程序将在适当的时间和地点安装它以执行自定义逻辑。
我们的自定义Java类需要封送和取消封送XML,为此它使用JAXB。因此,它需要一个JAXB上下文。
我在每次调用时都天真地调用JAXBContext.newInstance(MyClass.class)
,但不是很快发现这是内存泄漏的众所周知的秘诀。通常的做法是使一个(或最多只有几个)JAXB上下文在整个应用程序中共享。
很好,除了调用我的类的第三方应用程序之外,每个调用都是在对该调用私有的新ClassLoader实例上进行的。
因此,即使我将JAXBContext
放在static
字段或static HashMap<>
中,它对于调用仍然是私有的!
我如何在从私有ClassLoader实例实例化的类中创建要在JVM之间共享的单例?
我正在考虑两种可能的思路,但是我想就如何使它们中的任何一种或任何人使用的完全不同的方法提出建议。
我有三个想法:
在JVM类中的某个地方可以写一个对象。例如,如果System.setProperty
可以写Object
的实例,而不仅仅是String
,则想法是创建JAXB上下文并将其放在属性中,因为可以确定System
已经被实例化并自定义类加载器实例将继承它。但是System.setProperty
不会采用Object
值,因此我不知道执行此操作的实用方法。
以某种方式强制将类加载到我可以通过JAXB上下文存储的父类或根类加载器上。我不知道该怎么做。
使用ThreadLocal来存储JAXBContexts。我不认为每个调用都是一个全新的线程(它们可能会从线程池中重复使用),因此这可能是限制我的上下文的方式。但是如何创建ThreadLocal变量,以便其在实例之间共享?似乎这给我带来了同样的问题。
非常感谢您的帮助。由于项目的截止日期,我需要尽快对此做出答复。我无法立即为新问题设置赏金,但是当SO允许时,我会很乐意在可接受的答案上发送额外的代表。
听起来您的代码在第3方应用程序中被沙箱化。因此,使用static
或ThreadLocal
将无济于事,因为它们仅存在于相同的classloader
中,并且如果classloader
发生了更改,则上下文将丢失。
最接近的解决方案是将您的上下文注入到应用程序代码中。这不是最好的主意,因为它可能会受到外界的影响并产生意想不到的后果。请注意,这意味着您在classloader
中创建的值将保留在应用程序中,因此创建的classloader
将永远不会被垃圾回收。还有JAXB
jar来源的问题。我假设是从您的代码而不是第三方。因此,每次将jar加载到不同的类加载器中,以便从那里共享对象可能会出现问题,并需要一些代理。
老实说,会有很多无法预料的结果。
最好的想法是请第三者为您提供一些API来启用它。
继续之前,让我们看看其他选项:
JAXB
的替代品?不会出现相同的内存泄漏问题的东西。 注入