To prevent a memory leak, the JDBC Driver has been forcibly unregistered

后端 未结 14 1475
执念已碎
执念已碎 2020-11-22 02:15

I am getting this message when I run my web application. It runs fine but I get this message during shutdown.

SEVERE: A web application registered the

相关标签:
14条回答
  • 2020-11-22 03:21

    Although Tomcat does forcibly deregister the JDBC driver for you, it is nonetheless good practice to clean up all resources created by your webapp on context destruction in case you move to another servlet container which doesn't do the memory leak prevention checks that Tomcat does.

    However, the methodology of blanket driver deregistration is dangerous. Some drivers returned by the DriverManager.getDrivers() method may have been loaded by the parent ClassLoader (i.e., the servlet container's classloader) not the webapp context's ClassLoader (e.g., they may be in the container's lib folder, not the webapp's, and therefore shared across the whole container). Deregistering these will affect any other webapps which may be using them (or even the container itself).

    Therefore, one should check that the ClassLoader for each driver is the webapp's ClassLoader before deregistering it. So, in your ContextListener's contextDestroyed() method:

    public final void contextDestroyed(ServletContextEvent sce) {
        // ... First close any background tasks which may be using the DB ...
        // ... Then close any DB connection pools ...
    
        // Now deregister JDBC drivers in this context's ClassLoader:
        // Get the webapp's ClassLoader
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        // Loop through all drivers
        Enumeration<Driver> drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            if (driver.getClass().getClassLoader() == cl) {
                // This driver was registered by the webapp's ClassLoader, so deregister it:
                try {
                    log.info("Deregistering JDBC driver {}", driver);
                    DriverManager.deregisterDriver(driver);
                } catch (SQLException ex) {
                    log.error("Error deregistering JDBC driver {}", driver, ex);
                }
            } else {
                // driver was not registered by the webapp's ClassLoader and may be in use elsewhere
                log.trace("Not deregistering JDBC driver {} as it does not belong to this webapp's ClassLoader", driver);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 03:22

    I found that implementing a simple destroy() method to de-register any JDBC drivers works nicely.

    /**
     * Destroys the servlet cleanly by unloading JDBC drivers.
     * 
     * @see javax.servlet.GenericServlet#destroy()
     */
    public void destroy() {
        String prefix = getClass().getSimpleName() +" destroy() ";
        ServletContext ctx = getServletContext();
        try {
            Enumeration<Driver> drivers = DriverManager.getDrivers();
            while(drivers.hasMoreElements()) {
                DriverManager.deregisterDriver(drivers.nextElement());
            }
        } catch(Exception e) {
            ctx.log(prefix + "Exception caught while deregistering JDBC drivers", e);
        }
        ctx.log(prefix + "complete");
    }
    
    0 讨论(0)
提交回复
热议问题