gpt4 book ai didi

java - 通过资源加载 jdbc 驱动程序 (Tomcat 7)

转载 作者:行者123 更新时间:2023-11-28 21:55:16 25 4
gpt4 key购买 nike

我正在尝试使用 tomcat jdbc 连接池,我在我的应用程序 context.xml 文件中定义了它。

<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.DriverSpy 类在log4jdbc4-1.2.jar 中定义,它位于我的application 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 为 null,并且正在尝试通过 Class.forName(driverClassName) 加载驱动程序类。据我了解,在这种情况下,驱动程序类正在加载与 BasicDataSource 相同的类加载器实例。这是 StandardClassLoader,如果我的 jar 在 tomcat 库中,它将加载类。在我的例子中,抛出异常并使用 Thread.currentThread().getContextClassLoader(),它是 WebappClassLoader 实例,可以从 webapp lib 加载类,它确实如此。所以我很困惑。为什么说,如果我使用来自容器资源的数据源,我必须将我的驱动程序类放在 tomcat 库中。

求解释,谢谢

最佳答案

Tomcat 自动将容器管理的连接池添加到 jaxaz.sql.DataSource 类型的每个资源中。提供此池的库(Commons DBCP 的重命名版本的包)由共享类加载器加载(在默认配置中与公共(public)加载器相同)。池实现需要能够加载已配置的 JDBC 驱动程序,并且共享(和公共(public))加载器对 Web 应用程序类加载器不可见。因此,带有 JDBC 驱动程序的 JAR 需要位于 $CATALINA_BASE/lib 目录中,以便可以加载。

但是,截至r754776 ,如果 DBCP 无法加载指定的驱动程序,则回退到 Thread 的上下文类加载器。如果线程上下文类加载器设置为 Web 应用程序的类加载器,则可以加载驱动程序。此更改包含在 DBCP 1.31.4 中,这意味着它包含在 5.5.306.0.27 中code> 和每个 7.0.x 版本。它也将出现在每个 8.0.x 版本中。

MarkMail 查询量的相当不科学的观察表明,Tomcat 用户邮件列表中的 ClassNotFoundException 问题有所减少,但这同样可能取决于人更加意识到这个问题。

我想最根本的问题是这可靠吗?如果 DataSource 始终在线程上下文类加载器是 Web 应用程序类加载器时实例化,那么它将是可靠的。对这些资源的访问是通过 JNDI 进行的,这取决于正确设置的线程上下文类加载器。如果不是 - JNDI 将无法定位 Web 应用程序资源。在此基础上,这应该可行。

全局资源(显然)仍然需要位于 $CATALINA_HOME/lib 中的 JDBC 驱动程序

可能导致问题的场景是如果 JDBC 驱动程序 JAR 存在于 $CATALINA_HOME/lib 和 WEB-INF/lib。如果 Web 应用程序尝试转换为特定于数据库的对象,那么事情将会失败,因为这将尝试将共享加载器加载的类转换为 Web 应用程序类加载器加载的同名类,该类将始终失败。

简而言之:

  • 不要在 WEB-INF/lib$CATALINA_[HOME|BASE]/lib 中安装 JDBC 驱动程序的长期建议
  • 6.0.27 开始,可以将 JDBC 驱动程序打包到 Web 应用程序中,一切仍然有效。

对于最初的错误/不完整答案深表歉意。这不是我第一次完全忘记我所做的 promise ,我怀疑这不会是最后一次。

关于java - 通过资源加载 jdbc 驱动程序 (Tomcat 7),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19431102/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com