MemoryLeakProtectionとJDBC2

http://d.hatena.ne.jp/muimy/20100918/1284812424
のつづき


どうも、WEB-INF/libにJDBCドライバ置かずに、Tomcatのlibに置いたら、怒られないようだ


汎用的なやつをTomcatが勝手に呼んでくれないのは、クラスローダーがらみの問題ぽい。
registerDriverするのとunregisterDriverするのは同じクラスローダーである必要があるとか


Tomcatのソースちょっと追ってみたが、警告を出しているのは、
TomcatのWebappClassLoader#clearReferencesJdbcメソッド内の以下の部分

for (String name : driverNames) {
    log.error(sm.getString("webappClassLoader.clearJbdc",
            contextName, name));
}


で、その前にJdbcLeakPrevention#clearJdbcDriverRegistrations を呼び出していて、中でやってるのがこれ

public class JdbcLeakPrevention {

    public List clearJdbcDriverRegistrations() throws SQLException {
        List driverNames = new ArrayList();

        // This will list all drivers visible to this class loader
        Enumeration drivers = DriverManager.getDrivers();
        while (drivers.hasMoreElements()) {
            Driver driver = drivers.nextElement();
            // Only unload the drivers this web app loaded
            if (driver.getClass().getClassLoader() !=
                this.getClass().getClassLoader()) {
                continue;
            }
            driverNames.add(driver.getClass().getCanonicalName());
            DriverManager.deregisterDriver(driver);
        }
        return driverNames;
    }
}

JDBCドライバをロードしたクラスローダーと
JdbcLeakPreventionクラスをロードしたクラスローダー(StandardClassLoader?)が同じだったらunregisterDriverして、そうでなかったら、リストにつっこんで返す。
で、返されたドライバーが先のエラー出力の対象になる


WEB-INF/libにおいたJARをロードするクラスローダーってデフォでWebappClassLoaderなんだから、WebappClassLoaderでロードされたやつもunregisterDriverしてくれてもいいような気がするけど。


参考
http://d.hatena.ne.jp/tksmd/20100717#p1
http://d.hatena.ne.jp/TAKESHI/20100217/1266417114
http://d.hatena.ne.jp/c9katayama/20100715/1279162138