Wie wird der Verbindungspool beim Entladen des Kontexts heruntergefahren?

Nachdem ich mehrere Webapps entwickelt hatte, die alle ein ähnliches Setup mit spring, hibernate und c3p0 als Verbindungspool hatten, wollte ich ein Problem untersuchen, das mir jedes Mal auffiel: Connectionpool behält die Verbindungen bei, bis Sie Tomcat (oder Ihren Anwendungsserver) herunterfahren.

Heute erstelle ich das grundlegendste Projekt, das ich mit diesen vier Abhängigkeiten machen konnte:

org.springframework:spring-web
org.springframework:spring-orm
org.hibernate:hibernate-core
c3p0:c3p0

(plus den spezifischen JDBC-Treiber).

Meine web.xml erstellt nur einen ContextLoaderListener, der den Anwendungskontext einrichtet.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/applicationContext.xml
    </param-value>
</context-param>

<listener>
    <listener-class>
        org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

Anwendungskontext besteht aus zwei Beans - Datenquelle und Sitzungsfactory:

<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
</bean>

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass">
        <value>org.postgresql.Driver</value>
    </property>
    <property name="jdbcUrl">
        <value>jdbc:postgresql://localhost/mydb</value>
    </property>
    <property name="user">
        <value>usr</value>
    </property>
    <property name="password">
        <value>pwd</value>
    </property>
</bean>

Wenn ich die Webapp starte und entweder in die MBeans von jconsole schaue oder mein DBMS auf offene Verbindungen überprüfe, bemerke ich die drei anfänglichen Verbindungen, die von c3p0 hergestellt wurden.

PROBLEMBESCHREIBUNG: Wenn ich Tomcat auffordere, die Webapp zu stoppen, bleiben sie weiterhin bestehen!

Ich habe einen weiteren ServletContextListener erstellt, in dem nur die contextDestroyed-Methode implementiert ist, und die sessionFactory programmgesteuert heruntergefahren (und die Registrierung der JDBC-Treiber aufgehoben, was ebenfalls nicht automatisch erfolgt). Code ist:

@Override
public void contextDestroyed(ServletContextEvent sce) {

    ...
    sessionFactory().close();

    // deregister sql driver(s)
    Enumeration<Driver> drivers = DriverManager.getDrivers();
    while (drivers.hasMoreElements()) {
        Driver driver = drivers.nextElement();
        try {
            DriverManager.deregisterDriver(driver);
            log.info("deregistering jdbc driver: " + driver);
        } catch (SQLException e) {
            log.error("error deregistering jdbc driver: " + driver, e);
        }
    }
}

Aber ist das wirklich so? Gibt es keinen eingebauten Mechanismus, den ich nicht kenne?

Antworten auf die Frage(1)

Ihre Antwort auf die Frage