@ResourceアノテーションでDataSourceを注入してみる
TweetPosted on Sunday Feb 02, 2014 at 05:23PM in Technology
直接JDBCを使う必要がでてきた時用。
環境
- WildFly8.0.0.CR1
- Oracle JDK7u51
- PostgreSQL 9.2.4
準備
データソースを確認
こんなデータソースを使ってみることにする
[standalone@localhost:9990 /] /subsystem=datasources/data-source=TestDS:read-attribute(name=jndi-name) { "outcome" => "success", "result" => "java:jboss/jdbc/TestDS" } [standalone@localhost:9990 /]
HogeServlet.java
このサーブレットにDataSourceを注入します。try-with-resourcesが便利ですね。@Resourceアノテーションのlookup属性には、“java:comp/env/“の後にXMLファイルで定義した論理名を書く
package com.example; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.annotation.Resource; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; @WebServlet("/HogeServlet") public class HogeServlet extends HttpServlet { @Resource(lookup = "java:comp/env/jdbc/hoge") DataSource dataSource; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try(PrintWriter pw = response.getWriter(); Connection cn = dataSource.getConnection(); Statement st = cn.createStatement(); ResultSet rs = st.executeQuery("select now()")){ while(rs.next()){ pw.write(String.valueOf(rs.getTimestamp(1))); } }catch(SQLException e){ throw new ServletException(e); } } }
web.xml
この環境の場合はなくても動くようだが一応。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <resource-ref> <res-ref-name>jdbc/hoge</res-ref-name> <res-type>javax.sql.DataSource</res-type> </resource-ref> </web-app>
jboss-web.xml
WEB-INFの下に置く。ここでデータソースのJNDI名とResourceアノテーションのlookup属性で指定した名前のひも付けを行う。
<?xml version="1.0" encoding="UTF-8"?> <jboss-web> <resource-ref> <res-ref-name>jdbc/hoge</res-ref-name> <res-type>javax.sql.DataSource</res-type> <jndi-name>java:jboss/jdbc/TestDS</jndi-name> </resource-ref> </jboss-web>
動かしてみる
テストの際はどうするか
jboss-web.xmlを別のものに差し替えればOK。HogeServletには手を入れずに参照するDBを切り替えることができる。
備考
JPAのpersistence.xmlからはweb.xmlとjboss-web.xmlで定義した論理名を参照できない
persistence.xmlからもweb.xmlとjboss-web.xmlで定義した論理名 “jdbc/hoge” を使う事が出来れば、jboss-web.xmlを差し替えるだけでJPAから参照するデータソースも切り替えられるので楽だなと思ったのだが、どうやらそれは出来ないらしい[2]。“java:comp/env/jdbc/hoge” とかも試してみたが駄目だった。persistence.xmlにはAPサーバに定義してあるJNDI名を直接指定してやる必要があるみたい。残念。WebSphereだとできたりするみたいだけど一般的には駄目っぽい[5]。
今回の例だとこう書いてやる必要がある。
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> <persistence-unit name="datasource"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:jboss/jdbc/TestDS</jta-data-source> </persistence-unit> </persistence>
ただアプリケーションローカルでweb.xmlかアノテーションで定義したデータソースを使う場合は共用が可能らしい[3]。アプリの資源に接続情報べた書きになるので避けたい気もするが用途によっては良いのかもしれない。
@Resourceで直接JNDI名を参照する
特に論理名を通じて利用する必要がないなら、HogeServlet.javaで以下のようにすれば直接JNDI名からデータソースを拾って来れる。jboss-web.xmlもweb.xmlも不要になる。
ただし複数箇所でJNDI名の直書きが発生するのはあまりよろしくないので、CDIのProducerを使うか、前述の手段で論理名を通して参照した方が良いような気はする。
package com.example; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import javax.annotation.Resource; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.sql.DataSource; @WebServlet("/HogeServlet") public class HogeServlet extends HttpServlet { @Resource(lookup="java:jboss/jdbc/TestDS") DataSource dataSource; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try(PrintWriter pw = response.getWriter(); Connection cn = dataSource.getConnection(); Statement st = cn.createStatement(); ResultSet rs = st.executeQuery("select now()")){ while(rs.next()){ pw.write(String.valueOf(rs.getTimestamp(1))); } }catch(SQLException e){ throw new ServletException(e); } } }
参考文献
Tags: wildfly