3

I am running my application on GlassFish, I use Spring Security and Hibernate. When I run the application the following warning and errors will be shown on GlassFish console. How can I avoid them?

WARNING:   The web application [] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.
SEVERE:   The web application [] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@1087985b]) and a value of type [org.hibernate.internal.SessionImpl] (value [SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
SEVERE:   The web application [] created a ThreadLocal with key of type [net.sf.json.AbstractJSON$1] (value [net.sf.json.AbstractJSON$1@362386d7]) and a value of type [java.util.HashSet] (value [[]]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
SEVERE:   The web application [] created a ThreadLocal with key of type [net.sf.json.AbstractJSON$1] (value [net.sf.json.AbstractJSON$1@362386d7]) and a value of type [java.util.HashSet] (value [[]]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

hibernate.cfg.xml

<hibernate-configuration>

    <session-factory>

        <!-- Database connection settings -->
        <property name="connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
        <property name="connection.url">
            jdbc:mysql://localhost:3306/myproject
        </property>
        <property name="connection.username">root</property>
        <property name="connection.password"></property>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">12</property>

        <!-- SQL dialect -->
        <property name="dialect">
            org.hibernate.dialect.MySQLDialect
        </property>



        <!-- Enable Hibernate's automatic session context management -->
        <property name="current_session_context_class">thread</property>

<!--         Disable the second-level cache -->

<!-- <property name="cache.provider_class">
            org.hibernate.cache.EhCacheProvider
        </property>

        <property name="hibernate.cache.use_query_cache">true</property>-->


        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

HibernateUtil.java

public class HibernateUtil {

   private static ServiceRegistry serviceRegistry;
   private static final ThreadLocal<Session> threadLocal = new ThreadLocal();
   private static SessionFactory sessionFactory;

   private static SessionFactory configureSessionFactory() {
        try {
            Configuration configuration = new Configuration();
            configuration.configure();
            serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();

            sessionFactory = configuration.buildSessionFactory(serviceRegistry);

            return sessionFactory;
        } catch (HibernateException e) {
            System.out.append("** Exception in SessionFactory **");
            e.printStackTrace();
        }
       return sessionFactory;
  }     

  static {
    try {
      sessionFactory = configureSessionFactory();
    } catch (Exception e) {
      System.err.println("%%%% Error Creating SessionFactory %%%%");
      e.printStackTrace();
    }
  }

  private HibernateUtil() {
  }

  public static SessionFactory getSessionFactory() {
    return sessionFactory;
  }

  public static Session getSession() throws HibernateException {
    Session session = threadLocal.get();

    if (session == null || !session.isOpen()) {
      if (sessionFactory == null) {
        rebuildSessionFactory();
      }
      session = (sessionFactory != null) ? sessionFactory.openSession() : null;
      threadLocal.set(session);
    }

    return session;
  }

  public static void rebuildSessionFactory() {
    try {
      sessionFactory = configureSessionFactory();
    } catch (Exception e) {
      System.err.println("%%%% Error Creating SessionFactory %%%%");
      e.printStackTrace();
    }
  }

  public static void closeSession() throws HibernateException {
    Session session = (Session) threadLocal.get();
    threadLocal.set(null);

    if (session != null) {
      session.close();
    }
  }
}
Roman C
  • 49,761
  • 33
  • 66
  • 176
AlexCartio1
  • 238
  • 3
  • 9
  • 29
  • 1
    I know from personal experience that the one about the JDBCDriver isn't worth worrying about. Basically it means that you didn't close your database connection before your program ended. – JamesENL Feb 28 '14 at 07:48
  • Along as you are configured Spring to deregister driver consult the the Spring team why not this happened. – Roman C Feb 28 '14 at 12:06
  • See [this](http://stackoverflow.com/q/3320400/1391249) question. – Tiny Feb 28 '14 at 17:18

3 Answers3

8

These are error messages that can happen in the case of application redeployments while the server is kept running.

If it's a shutdown scenario or a development redeployment these messages can be safely ignored, they only become important if you need redeployments in production, which is rare. Most of the times even in production we want to stop the server process and fully restart it. This is some details on each of the messages meaning:

Message 1 - driver not unregistered when the application stopped:

WARNING: The web application [] registered the JDBC driver [com.mysql.jdbc.Driver] but failed to unregister it when the web application was stopped. To prevent a memory leak, the JDBC Driver has been forcibly unregistered.

JDBC drivers are registered at startup in a singleton at the level of the JVM, and this is meant to be done by the server, by publishing the driver jar in a folder at the server level.

In this case the application seems to carry the driver itself, which is not the way drivers are meant to be deployed.

To fix this remove the driver from the application and register it at the level of the server instead. If multiple applications have the same driver this will also cause memory leaks - see this answer as well.

Message 2 - ThreadLocal not cleaned up:

SEVERE: The web application [] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@1087985b]) and a value of type [org.hibernate.internal.SessionImpl] but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.

This means that one application spring thread stored a Hibernate session in the thread (each thread as a data store where things can be attached via ThreadLocal).

But the thread did not clean up the session when the application was restarted, so this variable stored at the thread can be visible AFTER the redeployment when the thread gets reused.

This might be surprising but worst the session was pointing to other objects, which themselves where pointing to classes, which where pointing to the old classloader before the redeploy.

This means a large portion of the object tree will NOT be garbage collected due to this leaked 'link' to the objects of the previous deployment. The result is a ClassLoader Memory Leak.

The message says that this scenario MIGHT happen due to uncleaned ThreadLocals, and that some preventive measures are going to be put in place (start killing threads and creating new ones instead of pooling, to get rid of the leaked thread locals).

As a summary, these messages can be safely ignored if you don't need redeployments in production and always restart the server.

Community
  • 1
  • 1
Angular University
  • 42,341
  • 15
  • 74
  • 81
  • great thanks for your comprehensive answer, I have another question which software do you suggest to use for testing? Java web applications? – AlexCartio1 Mar 09 '14 at 22:28
  • In my case, I need redeployments in production. Is there a way where I can manually clean up these threadlocals? – mpmp Jul 29 '16 at 18:27
3

To get rid of the JDBC driver warning, run the following on application shutdown:

String url = "your JDBC url";
Driver driver = DriverManager.getDriver(url);
DriverManager.deregisterDriver(driver);

If you are using Spring beans, you can put this in the destroy() method of a DisposableBean.

In a servlet environment, you can use a ServletContextListener:

public class CleanupListener implements ServletContextListener {

    public void contextDestroyed(ServletContextEvent arg0) {
        // enter cleanup code here
    }

    public void contextInitialized(ServletContextEvent arg0) { }
}

Set it up in web.xml:

<listener>
    <listener-class>com.example.CleanupListener</listener-class>
</listener>
holmis83
  • 15,922
  • 5
  • 82
  • 83
  • thanks, what do you mean by running this when app is shutdown? how about the second issue? – AlexCartio1 Mar 03 '14 at 03:21
  • @AlexCartio1 You can register a listener in the webapp that is invoked when the application is shutting down, where you can put cleanup code. For Spring applications you can use `DisposableBean`. If not Spring but in a servlet environment, you can use `ServletContextListener`. – holmis83 Mar 03 '14 at 11:13
  • would you give me an example of such listener? – AlexCartio1 Mar 09 '14 at 22:33
  • @AlexCartio1 Expanded my answer. – holmis83 Mar 10 '14 at 08:27
1

JDK6 onward the JDBC driver automatically get loaded if any Driver class found in classpath without Class.forName() method and It may lead the such error messages. Better to write a Listener for your application and de-register every driver at the time of application shutdown. You can get all registered driver using DiverManager#getDrivers() method and can de-register one by one.

Naveen Ramawat
  • 1,425
  • 1
  • 15
  • 27
  • whould you give me an example of such listener? – AlexCartio1 Mar 09 '14 at 22:30
  • 1
    Please test with ServletContextListener and de-register your driver at the time of context destroy. You can find the sample example of ServletContextListener at http://www.mkyong.com/servlet/what-is-listener-servletcontextlistener-example/ ... – Naveen Ramawat Mar 10 '14 at 05:27