Jak zamknąć pulę połączeń podczas rozładowywania kontekstu?

po opracowaniu kilku aplikacji internetowych, które wszystkie miały podobną konfigurację z wiosną, hibernacja i c3p0 jako połączenie, chciałem zbadać problem, który zauważyłem za każdym razem: Connectionpool zachowuje połączenia, dopóki nie zamkniesz tomcata (lub serwera aplikacji).

Dzisiaj tworzę najbardziej podstawowy projekt, jaki mogłem wykonać w tych czterech zależnościach:

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

(plus konkretny sterownik JDBC).

Mój plik web.xml tworzy tylko ContextLoaderListener, który konfiguruje kontekst aplikacji.

<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>

kontekst aplikacji składa się z dwóch ziaren - źródła danych i fabryki sesji:

<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>

Kiedy uruchamiam aplikację webapp i sprawdzam MBeans jconsole lub sprawdzam mój DBMS pod kątem otwartych połączeń, zauważam trzy początkowe połączenia wykonane przez c3p0.

PROBLEM: Kiedy mówię kocurowi, aby zatrzymał aplikację internetową, nadal pozostają!

Stworzyłem inny ServletContextListener, który ma zaimplementowaną tylko metodę contextDestroyed i programowo wyłącza sessionFactory (a także wyrejestrowuje sterowniki JDBC, które również nie są wykonywane automatycznie). Kod to:

@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);
        }
    }
}

Ale czy to naprawdę to? Czy nie ma wbudowanego mechanizmu, którego nie znam?

questionAnswers(1)

yourAnswerToTheQuestion