图书馆关闭程序,在一个“正常”的Java应用程序和Web应用程序运行良好

马克Rotteveel:

我保持一个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.DataSource),而JDBC java.sql.Driver实现未注册。

  • 包括javax.servlet.ServletContextListener带注释的实现@WebListener与将删除关机钩执行shutdown逻辑本身的驱动程序。

    如果驱动程序部署到服务器作为一个整体,而不是一个特定的Web应用程序(虽然这些并发症是可以解决的)这个选项有并发症。

有没有在Java中我关机机制忽略了,可能是适合我的需要?

托马斯Linkowski:

我试图想出解决办法,因为这似乎是这样一个有趣的案例。我在这里发布我发现,虽然我觉得我可能还是有误解的东西,或者做了一些太过牵强简化。其实,这也有可能是我完全误解了你的情况,这答案是没有用的(如果是的话,我道歉)。

我在这里组装什么是基于两个概念:

  • 应用服务器的全局状态(我用的System.props,但它可能不是最好的选择-也许是一些临时文件会做的更好)
  • 容器专用的全局状态(这意味着由容器特定的加载的所有类ClassLoader

我提出了一个EmbeddedEngineHandler.loadEmbeddedEngineIfNeeded将被调用的方法:

  • 你的驱动程序在注册过程中
  • javax.sql.DataSource实现静态初始化(如果这整个DataSource产权相关事情的作品这样-我很少知道它)

如果我这样做是正确,你会不会需要调用Runtime.removeShutdownHook的。

那我不确定这里的主要事情是这样的-如果司机在全球部署任何Servlet初始化之前,将它注册?如果没有,那么我听错了,这是行不通的。但也许检查ClassLoaderEmbeddedEngineHandler可以帮助呢?


这就是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;
    }
}

这就是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();
        }
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何创建一个Web应用程序以在线编译和运行Java / C / PHP代码?

Java Web应用程序的关闭挂钩

Java Web应用程序初始化和关闭

从另一个Java应用程序启动Java应用程序

添加一个Java程序以在Android Studio应用程序中运行

如何使用带有数据库的Rest Api设计图书馆应用程序

如何从laravel Web应用程序创建一个Android应用程序?

单击关闭一个闪亮的应用程序

创建一个简单的python Web应用程序

屏幕关闭或打开另一个应用程序时如何保持应用程序运行?

从您的应用程序中关闭另一个应用程序?

在应用程序中导入我的图书馆

如何在不同的Web应用程序中使用一个angularjs应用程序?

如何从主应用程序运行另一个应用程序的迁移

与我的应用程序交流图书馆服务的最佳方法

从我的应用程序中关闭一个应用程序

如何从当前应用程序运行另一个应用程序?

图书馆可以注册应用程序以获得通知吗?

每天自动运行一个应用程序

(iPhone)从另一个无法正常运行的应用程序启动

我只想运行一个应用程序

从图书馆项目扩展应用程序

MVC Web 应用程序和 API Web 应用程序可以在同一个池中运行吗?

Elixir 应用程序运行一个 PHP 脚本

运行一个简单的 Falcon 应用程序

tizen Web 应用程序,启动另一个 Web 应用程序

从另一个 Web 应用程序调用 Web 应用程序

一个 Web 应用程序是否可以有多个 azure 广告应用程序?

从浏览器运行我的 VodaPay 小程序 web-view 应用程序时,我无法访问我的图书馆