2017-06-03 77 views
2

我想在java中开发一个DB-Agnostic应用程序。我选择了休眠作为ORM。 jdbc的问题在于,它只是一个接口,我们需要类路径中db的驱动程序类。由于数据库应该是可配置的,我必须去动态加载驱动程序类的数据库。 (用户应该将驱动程序类保存在一个文件夹中,并且应该动态加载) 以下是我的代码。数据库驱动类动态加载

File driverJar = new File("E:\\Jomon\\backup_2017_05_25\\2.2\\WS\\2.2_1\\lib\\Drivers\\postgresql-42.1.1.jar"); 
URL[] urls = new URL[] { driverJar.toURL() }; 
URLClassLoader classLoader = new URLClassLoader(urls,DBUtils.class.getClassLoader()); 
Class.forName("org.postgresql.Driver", true, classLoader); 

到现在为止没有错误。 但之后,当初始化hibernate连接时,我得到错误java.lang.ClassNotFoundException:org.postgresql.Driver。

我可以知道这里有什么问题。

+0

您错过了类路径中的Postgres驱动程序,因为错误代表 –

+0

我选择了这种类加载方式,只是为了避免将jar保存在类路径中以及我的可运行jar。 如果我这样做,如果应用程序用户计划使用oracle比postgres,我必须在其类路径中给予另一个带有oracle驱动程序的可运行jar,这在我的情况下是不可能的。 我正在做的是让用户将jar保存在一个文件夹中,提供另一个配置文件的jar路径和驱动程序类名,并在应用程序的初始化面期间动态加载类。 – Jobs

+0

但是你在代码中硬编码文件名。如果你真的希望它是动态的,你应该遍历文件夹中的所有Jar文件 –

回答

2

最后,我自己得到了解决方案, 这里的问题是,我创建了一个新的类加载器并将jar加载到它中。

hibernate正在系统类加载器中搜索驱动程序类,而不是在用户定义的类加载器中搜索。

这里的问题可以通过将jar加载到系统类加载器来解决,如下所示。

File driverJar = new File("E:\\Jomon\\backup_2017_05_25\\2.2\\WS\\2.2_1\\lib\\Drivers\\postgresql-42.1.1.jar"); 
URL myJarFile = new URL("jar", "", "file:" + driverJar.getAbsolutePath() + "!/"); 
URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 

Class sysClass = URLClassLoader.class; 
Method sysMethod = sysClass.getDeclaredMethod("addURL", new Class[] { URL.class }); 
sysMethod.setAccessible(true); 
sysMethod.invoke(sysLoader, new Object[] { myJarFile }); 

Class.forName("org.postgresql.Driver", true, classLoader); // Now no error in this line. 
+0

很高兴看到你解决了它 – harshavmb

0

Hibernate总是会试图加载驱动程序从当前线程类加载器,并在你的情况下,它没有驱动程序。

你自己的类加载器工作正常,就在你初始化sessionFactory之前,把你的自定义加载器设置成contextClassLoader这样。

File f = new File("E:\\Jomon\\backup_2017_05_25\\2.2\\WS\\2.2_1\\lib\\Drivers\\postgresql-42.1.1.jar"); 
    URLClassLoader urlCl = new URLClassLoader(new URL[] { f.toURL() }, System.class.getClassLoader()); 
    Class postGreDriver = urlCl.loadClass("org.postgresql.Driver"); 
    System.out.println(postGreDriver.newInstance()); 

    Thread.currentThread().setContextClassLoader(postGreDriver); 

    //Hibernate can start 

    //you should restore your old classloader when hibernate services end 

这可能不是最好的解决方案。从这里得到这个片段discussion

希望这有助于!