Mar*_*eel 14 java servlets jdbc jna shutdown-hook
我维护一个JDBC驱动程序,它也具有通过本机库(通过JNA访问)提供的嵌入式数据库服务器模式.由于卸载其依赖项的顺序,作为卸载本机库本身的一部分完成的关闭在Windows上遇到问题.为了避免访问冲突或其他问题,我需要在卸载此库之前显式关闭嵌入式引擎.
鉴于其使用的性质,很难确定调用shutdown的适当时机,而我现在看到的普通Java应用程序的唯一正确方法是使用实现关闭逻辑Runtime.getRuntime().addShutdownHook的子类来注册一个关闭钩子Thread.
这对于一个普通的Java应用程序工作正常,但对于包括我的库作为应用程序(在部分Web应用程序WEB-INF/libWAR的),这将导致取消部署内存泄漏的关闭钩子将保持强引用我关机实现和Web应用程序的类加载器.
解决这个问题的合适和适当的方法是什么?我现在正在研究的选项是:
用java.sql.DriverAction.deregister()做清理工作.
不适合作为驱动程序将不会在正常的应用程序出口上注销.
使用java.sql.DriverAction.deregister()以除去关闭挂钩并执行关机逻辑本身.
DriverAction鉴于驱动程序仍然支持Java 7,使用有点问题,并且这个类是在JDBC 4.2(Java 8)中引入的.从技术上讲,这并不总是正确使用操作(JDBC驱动程序也可以在现有连接保持有效和正在使用时取消注册),并且可能在未注册javax.sql.DataSourceJDBC java.sql.Driver实现时使用(通过a )驱动程序.
包括使用驱动程序javax.servlet.ServletContextListener注释的实现@WebListener,该实现将删除关闭挂钩并执行关闭逻辑本身.
如果将驱动程序作为一个整体而不是特定的Web应用程序部署到服务器,则此选项会出现复杂情况(尽管可以解决这些复杂问题).
Java中是否有关闭机制我忽略了它可能适合我的需求?
我试图弄清楚这一点,因为这看起来很有趣。我在这里发布我的发现,尽管我觉得我可能仍然误解了某些东西,或者做了一些过于牵强的简化。实际上,也有可能我完全误解了你的情况,这个答案毫无用处(如果是这样,我深表歉意)。
我在这里收集的内容基于两个概念:
System.props,但它可能不是最好的选择 - 也许一些临时文件会做得更好)ClassLoader)我提出了一种EmbeddedEngineHandler.loadEmbeddedEngineIfNeeded方法,称为:
javax.sql.DataSource实现静态初始化程序中(如果这整个DataSource相关的事情是这样工作的 - 我对此知之甚少)Runtime.removeShutdownHook如果我没猜错的话,你就根本不需要打电话了。
我在这里不确定的主要问题是 - 如果驱动程序是全局部署的,它是否会在初始化任何 servlet 之前注册?如果不是,那么我就错了,这行不通。但也许检查一下ClassLoader会有EmbeddedEngineHandler帮助呢?
这是EmbeddedEngineHandler:
final class EmbeddedEngineHandler {
private static final String PREFIX = ""; // some ID for your library here
private static final String IS_SERVLET_CONTEXT = PREFIX + "-is-servlet-context";
private static final String GLOBAL_ENGINE_LOADED = PREFIX + "-global-engine-loaded";
private static final String TRUE = "true";
private static volatile boolean localEngineLoaded = false;
// LOADING
static void loadEmbeddedEngineIfNeeded() {
if (isServletContext()) {
// handles only engine per container case
loadEmbeddedEngineInLocalContextIfNeeded();
} else {
// handles both normal Java application & global driver cases
loadEmbeddedEngineInGlobalContextIfNeeded();
}
}
private static void loadEmbeddedEngineInLocalContextIfNeeded() {
if (!isGlobalEngineLoaded() && !isLocalEngineLoaded()) { // will not load if we have a global driver
loadEmbeddedEngine();
markLocalEngineAsLoaded();
}
}
private static void loadEmbeddedEngineInGlobalContextIfNeeded() {
if (!isGlobalEngineLoaded()) {
loadEmbeddedEngine();
markGlobalEngineAsLoaded();
Runtime.getRuntime().addShutdownHook(new Thread(EmbeddedEngineHandler::unloadEmbeddedEngine));
}
}
private static void loadEmbeddedEngine() {
}
static void unloadEmbeddedEngine() {
}
// SERVLET CONTEXT (state shared between containers)
private static boolean isServletContext() {
return TRUE.equals(System.getProperty(IS_SERVLET_CONTEXT));
}
static void markAsServletContext() {
System.setProperty(IS_SERVLET_CONTEXT, TRUE);
}
// GLOBAL ENGINE (state shared between containers)
private static boolean isGlobalEngineLoaded() {
return TRUE.equals(System.getProperty(GLOBAL_ENGINE_LOADED));
}
private static void markGlobalEngineAsLoaded() {
System.setProperty(GLOBAL_ENGINE_LOADED, TRUE);
}
// LOCAL ENGINE (container-specific state)
static boolean isLocalEngineLoaded() {
return localEngineLoaded;
}
private static void markLocalEngineAsLoaded() {
localEngineLoaded = true;
}
}
Run Code Online (Sandbox Code Playgroud)
这是ServletContextListener:
@WebListener
final class YourServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
EmbeddedEngineHandler.markAsServletContext();
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (EmbeddedEngineHandler.isLocalEngineLoaded()) {
EmbeddedEngineHandler.unloadEmbeddedEngine();
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
272 次 |
| 最近记录: |