如何在 Apache Tomcat 中部署 Marklogic XCC 库?
How to deploy the Marklogic XCC library in Apache Tomcat?
问题:
使用 WAR 文件(在 WEB-INF/classes 中)部署 XCC 库会在不重新启动整个 Tomcat 容器的情况下禁止 re-deployments/updates 该 webapp。它只是停止工作,因为仍然分配了资源,因此 Tomcat.
无法删除一些 JAR 文件
在 Tomcats lib 目录中部署库时(作为 JDBC 驱动程序),Tomcat 在 Tomcat 日志中写入内存泄漏警告,如下所示:
17-Mar-2016 10:58:45.683 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [api] appears to have started a thread named [Thread-4] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: java.lang.Thread.sleep(Native Method) com.marklogic.xcc.ContentSourceFactory$ConnectionCollector.run(ContentSourceFactory.java:449)
我发现了什么:
我做了一些调查,发现(至少在 XCC 8.0.3 中)有一个在 ContentSourceFactory 中启动的线程永远不会关闭。该线程正在影响 updates/re-deployments 个 servlet 并造成内存泄漏。我的快速解决方案是创建一个自定义的 ContentSourceFactory,它有一个在 servlet 停止时调用的关闭方法。
问题:
不幸的是,我没有在文档中找到任何线索。那么在 servlet 容器中使用 XCC 库 (8.x) 的官方方法是什么?
在 JVM 运行期间,此线程确实 运行 出现。我将为此打开一个缺陷。
根据 tomcat 中不同产品的类似问题经验得出的解决方法。数据库驱动器(特别是 JDBC)历来以这种方式存在问题。
将 xcc.jar 放入 tomcat 的 'shared library' class 路径而不是 WAR。一般不建议这样做——但 OTOH 这正是存在共享库 class 路径的原因——这允许重新部署您的应用程序。
只要您自己不共享活动连接对象,XCC 代码就是线程安全和上下文独立的,它应该可以正常工作。
还要确保您认真关闭或关闭所有响应对象,终结器可能需要很长时间才能启动。
-大卫
我的临时解决方案:
正如 DALDEI 所提到的,它看起来像是 XCC 库中的一个开放问题。为了做一个临时的解决方法,我根据原始来源 (8.0.4) 写了一个 DisposableContentSourceFactory
。代码可以在这里找到:https://gist.github.com/Mario-Eis/a16437c35d2aa097f668
该方法还有一个优势,因为它可以顺利集成到 IoC 上下文中,例如Spring国际奥委会。
@Configuration
public class XccContext {
@Bean(destroyMethod = "shutdown")
public DisposableContentSourceFactory contentSourceFactory() {
return DisposableContentSourceFactory.create();
}
@Bean
public ContentSource contentSource(XccConfiguration xccConfiguration, DisposableContentSourceFactory contentSourceFactory) throws XccConfigException {
return contentSourceFactory.newContentSource(xccConfiguration.connectionString());
}
@Bean(destroyMethod = "close")
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public Session marklogicSession(ContentSource contentSource) {
return contentSource.newSession();
}
}
为了确保官方静态 class 方法有点 "compatibility",我还包含了一个静态工厂方法 create()
.
如果有 public GIT 存储库,我可以提交拉取请求。
问题:
使用 WAR 文件(在 WEB-INF/classes 中)部署 XCC 库会在不重新启动整个 Tomcat 容器的情况下禁止 re-deployments/updates 该 webapp。它只是停止工作,因为仍然分配了资源,因此 Tomcat.
无法删除一些 JAR 文件
在 Tomcats lib 目录中部署库时(作为 JDBC 驱动程序),Tomcat 在 Tomcat 日志中写入内存泄漏警告,如下所示:
17-Mar-2016 10:58:45.683 WARNING [ContainerBackgroundProcessor[StandardEngine[Catalina]]] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [api] appears to have started a thread named [Thread-4] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread: java.lang.Thread.sleep(Native Method) com.marklogic.xcc.ContentSourceFactory$ConnectionCollector.run(ContentSourceFactory.java:449)
我发现了什么:
我做了一些调查,发现(至少在 XCC 8.0.3 中)有一个在 ContentSourceFactory 中启动的线程永远不会关闭。该线程正在影响 updates/re-deployments 个 servlet 并造成内存泄漏。我的快速解决方案是创建一个自定义的 ContentSourceFactory,它有一个在 servlet 停止时调用的关闭方法。
问题:
不幸的是,我没有在文档中找到任何线索。那么在 servlet 容器中使用 XCC 库 (8.x) 的官方方法是什么?
在 JVM 运行期间,此线程确实 运行 出现。我将为此打开一个缺陷。
根据 tomcat 中不同产品的类似问题经验得出的解决方法。数据库驱动器(特别是 JDBC)历来以这种方式存在问题。
将 xcc.jar 放入 tomcat 的 'shared library' class 路径而不是 WAR。一般不建议这样做——但 OTOH 这正是存在共享库 class 路径的原因——这允许重新部署您的应用程序。 只要您自己不共享活动连接对象,XCC 代码就是线程安全和上下文独立的,它应该可以正常工作。
还要确保您认真关闭或关闭所有响应对象,终结器可能需要很长时间才能启动。
-大卫
我的临时解决方案:
正如 DALDEI 所提到的,它看起来像是 XCC 库中的一个开放问题。为了做一个临时的解决方法,我根据原始来源 (8.0.4) 写了一个 DisposableContentSourceFactory
。代码可以在这里找到:https://gist.github.com/Mario-Eis/a16437c35d2aa097f668
该方法还有一个优势,因为它可以顺利集成到 IoC 上下文中,例如Spring国际奥委会。
@Configuration
public class XccContext {
@Bean(destroyMethod = "shutdown")
public DisposableContentSourceFactory contentSourceFactory() {
return DisposableContentSourceFactory.create();
}
@Bean
public ContentSource contentSource(XccConfiguration xccConfiguration, DisposableContentSourceFactory contentSourceFactory) throws XccConfigException {
return contentSourceFactory.newContentSource(xccConfiguration.connectionString());
}
@Bean(destroyMethod = "close")
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public Session marklogicSession(ContentSource contentSource) {
return contentSource.newSession();
}
}
为了确保官方静态 class 方法有点 "compatibility",我还包含了一个静态工厂方法 create()
.
如果有 public GIT 存储库,我可以提交拉取请求。