読者です 読者をやめる 読者になる 読者になる

nekop's blog

OpenShift / JBoss / WildFly / Infinispanの中の人 http://twitter.com/nekop

JBoss ASでコネクションクローズ漏れ検知

jboss

JBoss Advent Calendar 2011の10日目のエントリです。JBoss ASのデータソースその他のパラメータでStatementやResultSetのクローズ漏れをクローズするという機能を紹介しましたが、Connectionもクローズ漏れを検知してクローズする機能があります。

JDBCのConnectionは通常サーブレットEJBの内部でオープンされ、クローズされる、という形で利用されます。JBoss ASではこのConnectionのオープン処理をフックして記録しており、サーブレットEJBを抜ける時に内部でオープンされたコネクションがきちんとクローズされているかどうかをチェックしています。この機能はサーブレットEJBコンテナのプラグインレイヤで行っているため、例えばJMX上のスレッドや他のスレッド上ではこのConnectionもクローズ漏れチェックは機能しません。

$JBOSS_HOME/server/$PROFILE/deploy/jca-jboss-beans.xmlのCachedConnectionManager.debugにtrueが指定されている場合、Connectionもクローズ漏れチェックが有効です。falseを指定することで無効化できます。

実際にクローズ漏れが検出されると、"Closing a connection for you. Please close them yourself"というメッセージと共に、getConnection()をコールしたコードのスタックトレースが表示されます。

例えば、こんなJSPを書いてみます。このJSPではgetConnection()していますがそのまま放置してclose()を呼ばないままリクエスト処理を終了します。

(テスト目的でJSPを使ってスクリプトレットで書いていますが、良い子は無闇にJSPとか使わないようにしましょう)

<html 
  xmlns="http://www.w3c.org/1999/xhtml" 
  xmlns:jsp="http://java.sun.com/JSP/Page" 
  xmlns:c="http://java.sun.com/jsp/jstl/core"
  xml:lang="en" lang="en">
  <jsp:directive.page import="javax.sql.DataSource,javax.naming.InitialContext" />
  <jsp:scriptlet>
    String name = "java:DefaultDS";
    ((DataSource)new InitialContext().lookup(name)).getConnection();
  </jsp:scriptlet>
  <body>
    <p>ok</p>
  </body>
</html>

これをJBoss AS 6.1.0.Final上で実行してみるとConnectionのクローズ漏れを教えてくれます。

10:57:12,724 INFO  [org.jboss.resource.connectionmanager.CachedConnectionManager] Closing a connection for you.  Please close them yourself: org.jboss.resource.adapter.jdbc.jdk6.WrappedConnectionJDK6@150f4590: java.lang.Throwable: STACKTRACE
	at org.jboss.resource.connectionmanager.CachedConnectionManager.registerConnection(CachedConnectionManager.java:278) [:6.1.0.Final]
	at org.jboss.resource.connectionmanager.BaseConnectionManager2.allocateConnection(BaseConnectionManager2.java:524) [:6.1.0.Final]
	at org.jboss.resource.connectionmanager.BaseConnectionManager2$ConnectionManagerProxy.allocateConnection(BaseConnectionManager2.java:941) [:6.1.0.Final]
	at org.jboss.resource.adapter.jdbc.WrapperDataSource.getConnection(WrapperDataSource.java:89) [:6.1.0.Final]
	at org.apache.jsp.index_jsp._jspService(index_jsp.java:64)
	at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70) [:6.1.0.Final]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [:1.0.0.Final]
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:369) [:6.1.0.Final]
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:326) [:6.1.0.Final]
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:253) [:6.1.0.Final]
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [:1.0.0.Final]


JBoss AS 7.1.0.Beta1ではまだ同等の機能は実装されていないようです。