2004年7月18日

解決 Tomcat 重新部署 .war 後 DataSource 失效問題

若是依照 開啟 Tomcat 遠端部署功能 內所說的目錄設定方式架設網頁應用程式時,可能會發現 Tomcat 的資料庫連線池會在重新部署一個網頁應用程式後產生一個執行時期例外,它的 Log 就像是這樣的:

[ERROR] 2004-07-07 14:53:46,747 org.apache.jsp.Exception_jsp - Cannot create JDBC driver of class '' for connect URL 'null'
[ERROR] 2004-07-07 14:53:46,759 org.apache.jsp.Exception_jsp - org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:750)
org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:518)
tw.net.fitel.utility.InitialSQL.getDataSourceConnection(Unknown Source)
org.apache.jsp.passport_jsp._jspService(passport_jsp.java:108)
org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:133)
javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:311)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:301)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:248)
javax.servlet.http.HttpServlet.service(HttpServlet.java:856)
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:284)
...

查遍 Google 上可以發現一堆人有相同的問題,經多方測試後發現一個簡單的解決方式:『在 Server.xml 中加上 <DefaultContext>...</DefaultContext> 設定區段』。

在我的作法中,所有的 JNDI DataSource 都會放在 <GlobalNamingResources>...</GlobalNamingResources> 之中(因為我習慣將連接相同資料庫的應用系統放在同一台主機上),因此 <DefaultContext>...</DefaultContext> 中的設定只要將記錄在 <GlobalNamingResources>...</GlobalNamingResources> 的 Resources 連接過來即可,如範例:

<GlobalNamingResources>
     <Resource name="jdbc/mydbGlobal" auth="Container"
               type="javax.sql.DataSource"/>
     <ResourceParams name="jdbc/mydbGlobal">
         <parameter>
            <name>factory</name>
            <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
         </parameter>
         <parameter>
            <name>driverClassName</name>
            <value>oracle.jdbc.driver.OracleDriver</value>
         </parameter>
         <parameter>
            <name>url</name>
            <value>jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=xx.xx.xx.xx)(PORT=1521)))(CONNECT_DATA=(SID = myDatabase)))</value>
         </parameter>
         <parameter>
            <name>username</name>
            <value>myweb</value>
         </parameter>
         <parameter>
            <name>password</name>
            <value>myweb</value>
         </parameter>
         <parameter>
            <name>maxActive</name>
            <value>100</value>
         </parameter>
         <parameter>
            <name>maxIdle</name>
            <value>10</value>
         </parameter>
         <parameter>
            <name>maxWait</name>
            <value>10</value>
         </parameter>
      </ResourceParams>
  </GlobalNamingResources>

<Host name="app.foo.com" debug="0" appBase="/home/app" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false" >

<!-- 這是設定有關本站台的一般記錄保存方式 --> <!-- directory 若未指定絕對位址時,則採相對於 $CATALINA_HOME 路徑方式認定 --> <Logger className="org.apache.catalina.logger.FileLogger" directory="logs" prefix="app_log." suffix=".txt" timestamp="true"/>

<!-- 這是設定有關本站台的資源存取記錄保存方式 --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="app_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>

<!-- 這一段是用來設定所有 Context 共同遵守的設定 --> <DefaultContext crossContext="true" reloadable="true"> <ResourceLink name="jdbc/mydb" global="jdbc/mydbGlobal" type="javax.sql.DataSource" /> </DefaultContext>

<!-- 這一段是設定這個虛擬主機下有幾個 Web Application --> <Context path="/application" docBase="application" debug="5" reloadable="true" crossContext="true" > </Context> </Host>

完成設定後記得重啟 Tomcat ,再來若單獨 deploy 某一個 Context 時,就不會造成 JNDI 中記錄的 Database Source 失去消息了。

Enjoy it !