我正在编写一些gradle插件,现在遇到一个问题,即DriverManager没有看到buildscript依赖项中定义的JDBC驱动程序:
我有下一个build.gradle文件:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("com.h2database:h2:1.4.196")
}
}
plugins {
id "someplugin"
}
apply plugin: 'groovy'
当我调用扩展DefaultTask的任务中定义的命令时
DriverManager.getConnection("jdbc:h2:mem:", "sa", "")
我收到异常(exception)
No suitable driver found for jdbc:h2:mem:
当我对这些类进行单元测试时没有问题-仅当我调用调用DriverManager.getConnection的插件任务时才会发生。
我在这里想念什么?谢谢!
最佳答案
好吧,有一个答案说明为什么DriverManager
不能像您使用它那样工作,以及如何使其工作,还有一个答案,如何正确使用Groovy中的SQL(这是Gradle脚本的基础)。我将从使用Groovy使用SQL的正确方法开始:
从Gradle / Groovy正确使用SQL:
不幸的是,将驱动程序添加到buildscript类路径不足以使用Groovy Sql类,您需要将驱动程序添加到正确的类加载器中,否则它将无法正常工作。
除了将驱动程序添加到JVM ext目录外,您还可以像这样动态地执行此操作:
configurations { jdbc }
jdbc 'com.h2database:h2:1.4.196'
def sqlClassLoader = Sql.classLoader
configurations.jdbc.each { sqlClassLoader.addURL it.toURI().toURL() }
Sql.withInstance('jdbc:h2:mem:', 'sa', '', 'org.h2.Driver') {
it.execute 'your sql here'
}
正确使用
DriverManager
:由于Groovy的动态性,您不能像以前那样正确使用
DriverManager
。在您使用的方法中,DriverManager
尝试从调用堆栈中动态查找调用者类,然后使用该类的类加载器来查找数据库驱动程序。使用Groovy,这是一些动态代理类,因此无法在其类加载器中找到数据库驱动程序。如果改为给
DriverManager
正确的调用者类(如DriverManager.getConnection("jdbc:h2:mem:", [user: "sa", password: ""] as Properties, getClass())
),则它可以正常工作。或者,也可以不提供任何调用者类(例如DriverManager.getConnection("jdbc:h2:mem:", [user: "sa", password: ""] as Properties, null)
),在这种情况下,使用当前线程上下文类加载器,这也很好。在Gradle中自动查找驱动程序的问题:
加载类
DriverManager
时,它将扫描系统属性jdbc.drivers
和提供java.sql.Driver
服务的所有服务。它遍历那些找到的类并实例化它们。驱动程序本身通常会响应自己向DriverManager
注册,他们可以在此时进行操作,以便稍后可以自动查找,就像我上面建议的那样。现在的问题是,如果您正在使用Gradle守护程序(目前是默认设置),并在该守护程序中运行任何加载
DriverManager
的构建(例如,在您之前的尝试中),则该类已被加载。如果之后再将buildscript依赖项添加到H2中(或在不存在但已加载DriverManager
的位置后运行存在该构建的依赖项),则该类已被加载,并且不会查找类路径中现在存在的驱动程序。这里有一些可能的解决方法,没有明确命名驱动程序类,从最坏的解决方案到最好的解决方案:
DriverManager.loadInitialDrivers()
之前,请使用私有(private)方法getConnection
,以确保再次完成查找并自动添加了H2驱动程序。更好,但使用私有(private)方法。 ServiceLoader
将所有Driver
类加载到类路径中,以使其在DriverManager
调用之前向ServiceLoader.load(Driver.class).collect()
(例如getConnection
)进行自我注册。可能是最优雅的解决方案。 在此处显式命名驱动程序类的一些可能的解决方法:
getConnection()
使其在org.h2.Driver.toString()
进行自注册之前,只需加载类即可。getConnection()
使其在Class.forName 'org.h2.Driver'
进行自注册之前,只需加载类即可。关于jdbc - DriverManager在Gradle自定义插件的任务中看不到依赖项,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55262588/