【发布时间】:2017-09-25 20:13:17
【问题描述】:
如何在不使用数据源或任何与 GORM Hibernate 相关的情况下在 Grails 服务中创建类 groovy.sql.Sql 的实例?在我的 Grails 应用程序中,在我的 Service 类中,当我尝试创建 Sql 实例时出现异常:
Caused by: java.lang.ClassNotFoundException: org.postgresql.Driver
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at java_lang_ClassLoader$loadClass$1.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
at com.tav.admin.DbService.copyFileToTable(DbService.groovy:87)
似乎是类加载问题。这是服务方法。
long copyFileToTable(String sql, FileReader fileReader) {
println("System Class Loader: ${ClassLoader.getSystemClassLoader().getClass().getName()}")
println("Groovy Class Loader: ${Thread.currentThread().getContextClassLoader().getClass().getName()}")
Thread.currentThread().getContextClassLoader().loadClass(driverClassName)
ClassLoader.getSystemClassLoader().loadClass(driverClassName) // Note throws exception here!
props = new Properties()
props.setProperty('user', username)
props.setProperty('password', password)
PgConnection copyOperationConnection = (PgConnection) Sql.newInstance(url, props, driverClassName)
CopyManager copyManager = new CopyManager(copyOperationConnection)
return copyManager.copyIn(sql, fileReader)
}
输出:
System Class Loader: sun.misc.Launcher$AppClassLoader
Groovy Class Loader: groovy.lang.GroovyClassLoader
PostgreSQL 驱动程序已在 DriverManager 中注册。我可以在我的服务中使用注入的数据源,但我需要创建与 GORM Hibernate 无关的数据库的新连接以使用驱动程序特定功能(PostgreSQL CopyManager)。
在 DriverManager.isDriverAllowed() 中
Class.forName(driver.getClass().getName(), true, classLoader);
返回空值。
版本信息:Grails 2.5.1、Java jdk1.7.0_79、Groovy 2.0.6
我已将问题缩小到以下代码行:
ClassLoader.getSystemClassLoader().loadClass(driverClassName) // Note throws exception here!
似乎 Groovy/Grails 使用 GroovyClassLoader 加载 JDBC 驱动程序,但是当您尝试从 DriverManager.getConnection() 获取连接时,驱动程序管理器会尝试使用 System Class Loader 加载 JDBC 驱动程序。系统类加载器似乎不知道 Groovy 类加载器已经加载了该类。就像 DriverManager 和系统类加载器被沙箱化,远离 Groovy 加载的类。
【问题讨论】:
-
与您的问题无关,但仅供参考...
grailsApplication.config.dataSource.username和类似的问题有几个原因。有更好的方法可以做到这一点,其中一些在objectcomputing.com/products/grails/… 中进行了描述。 -
@JeffScottBrown 我看了你的视频并修改了代码以使用 Value 注释。
-
我在 Grails 应用程序中做了类似的事情,即在 Gorm 之外使用 groovy.sql.Sql,如果删除
ClassLoader.getSystemClassLoader().loadClass...部分并让它运行到Sql.newInstance...,会在哪里发生故障?在我的应用程序中,我不关心 ClassLoader 的东西,不确定您是出于演示目的展示它还是实际在代码中使用它。