数据库驱动程序级动态加载

时间:2017-06-03 17:37:18

标签: java classloader

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

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme" >

        <!--
             The API key for Google Maps-based APIs is defined as a string resource.
             (See the file "res/values/google_maps_api.xml").
             Note that the API key is linked to the encryption key used to sign the APK.
             You need a different API key for each encryption key, including the release key that is used to
             sign the APK for publishing.
             You can define the keys for the debug and release targets in src/debug/ and src/release/. 
        -->
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />

        <activity
            android:name=".MapsActivity"
            android:label="@string/title_activity_maps" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

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

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

2 个答案:

答案 0 :(得分: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.

答案 1 :(得分: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

获得此片段

希望这有帮助!!!