2013-10-17 59 views
1

我想使用tomcat jdbc連接池,並在我的應用程序context.xml文件中定義它。通過資源(Tomcat 7)加載jdbc驅動程序

<Context> 
    <Resource auth="Container" name="jdbc/iup" type="javax.sql.DataSource" 
       maxActive="300" maxIdle="30" maxWait="20000" 
       username="${db.username}" password="${db.password}" driverClassName="net.sf.log4jdbc.DriverSpy" 
       url="jdbc:log4jdbc:sqlserver://${db.server};databaseName=${db.name}"/> 
</Context> 

net.sf.log4jdbc.DriverSpylog4jdbc4-1.2.jar,其被放置在我的申請LIB文件夾中定義。對我來說它工作得很好。但here據說,帶驅動程序類的jar只能放在tomcat的lib文件夾中。

Tomcat使用它BasicDataSource類加載驅動程序:

if (driverClassName != null) { 
      try { 
       try { 
        if (driverClassLoader == null) { 
         Class.forName(driverClassName); 
        } else { 
         Class.forName(driverClassName, true, driverClassLoader); 
        } 
       } catch (ClassNotFoundException cnfe) { 
        driverFromCCL = Thread.currentThread(
          ).getContextClassLoader().loadClass(
            driverClassName); 
       } 
      } catch (Throwable t) { 
       String message = "Cannot load JDBC driver class '" + 
        driverClassName + "'"; 
       logWriter.println(message); 
       t.printStackTrace(logWriter); 
       throw new SQLNestedException(message, t); 
      } 
     } 

driverClassLoader爲空,而驅動程序類是嘗試通過Class.forName(driverClassName)被加載。據我所知,在這種情況下,驅動程序類正在加載與BasicDataSource相同的類加載器實例。這是StandardClassLoader,如果我的jar在tomcat庫中,它將加載這個類。在我的情況下,拋出異常,並使用Thread.currentThread().getContextClassLoader(),這是WebappClassLoader實例,並可以從Web應用程序庫中加載類,它會。所以我很困惑。爲什麼說,如果我從容器資源使用數據源,我必須將我的驅動程序類放在tomcat庫中。

請解釋一下,謝謝

回答

5

Tomcat的自動添加容器管理的連接池,以jaxaz.sql.DataSource類型的每個資源。提供此池的庫(Commons DBCP的軟件包重命名版本)由共享類加載器(在默認配置中與普通加載器相同)加載。池實現需要能夠加載配置的JDBC驅動程序,並且共享(和通用)加載程序不具有對Web應用程序類加載程序的可見性。因此,帶有JDBC驅動程序的JAR需要位於$CATALINA_BASE/lib目錄中,以便可以加載它。

但是,從r754776開始,如果DBCP無法加載指定的驅動程序,它將回退到Thread的上下文類加載器。如果線程上下文類加載器設置爲Web應用程序的類加載器,則可以加載驅動程序。此更改包含在DBCP 1.31.4之後,這意味着它包含在5.5.30之後,6.0.27之後以及每7.0.x發佈。它也將在每個8.0.x版本中發佈。

,相當不科學看看查詢量與MarkMail表明,出現了對Tomcat用戶郵件列表ClassNotFoundException問題有所減少,但它同樣可以下到人們更加意識到這個問題。

我猜根本的問題是這可靠嗎?如果DataSource總是在線程上下文類加載器是Web應用程序類加載器時實例化,那麼它將是可靠的。通過JNDI來訪問這些資源,這取決於正確設置的線程上下文類加載器。如果不是 - JNDI將無法​​找到Web應用程序資源。在此基礎上,這應該是正常的。

環球資源(顯然)仍然需要JDBC駕駛員位於$CATALINA_HOME/lib

的情況很可能會導致問題是,如果JDBC司機JAR存在於$CATALINA_HOME/lib and WEB-INF/lib。如果Web應用程序嘗試將其轉換爲數據庫特定的對象,那麼事情就會失敗,因爲這將嘗試將由共享加載器加載的類轉換爲由Web應用程序類加載器加載的同名類失敗。

因此,在短期:

  • 的長期建議不要有JDBC驅動程序在WEB-INF/lib$CATALINA_[HOME|BASE]/lib代表
  • 作爲6.0.27起,就可以打包在Web應用程序中的JDBC驅動程序和一切仍然有效。

抱歉,最初的錯誤/不完整的答案。這並不是我第一次完全忘記我做出的承諾,我懷疑它不會是最後一次。

+0

我知道。從代碼中可以看到,當通用加載程序無法加載驅動程序時,上下文類加載程序(指的是webapp classloader)會成功加載驅動程序。這就是爲什麼我很困惑 –

+0

嗯。讓我去挖掘源代碼。你確定你在使用Tomcat 7嗎?究竟是哪個版本? (Tomcat 8有上面的代碼,但Tomcat 7沒有 - 該源代碼片段從哪裏來?) –

+0

我使用的是7.0.27版本。此外,我已經檢查過版本6,並看到代碼的相同部分 –

相關問題