卸载Java11中由类加载器加载的dll

问题描述

我有一个场景,我需要使用Java11在sql Server上使用Windows身份验证来执行两次数据库连接。 最初,将为第一个调用加载sqljdbc_auth.dll,并且连接成功。但是,为了在不同的地方第二次建立连接,它抛出一个sqlException,说“另一个类加载器已经加载了sqljdbc_auth.dll”。 因此,我需要在两个调用之间卸载dll。

通过使用反射机制在类加载器上调用finalize(),直到Java8版本,都可以选择执行相同的操作,但是无法在Java11中找到替代方法

示例代码

在这里,我将sqljdbc_auth.dll放在PATH中,并将名为sql_jdbc.jar的jar放在URL列表中,并且它们与Java11兼容。

private static void loadFile(){
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();;
ClassLoader loader = new urlclassloader(urls,ClassLoader.getSystemClassLoader()); // here,urls is an array and contains only a single sql_jdbc.jar path in it
Thread.currentThread().setContextClassLoader(loader);
Driver driver = (Driver)loader.loadClass("com.microsoft.sqlserver.jdbc.sqlServerDriver").newInstance();
Connection connection = driver.connect("jdbc:sqlserver://IP-addr:1433;DatabaseName=db_name;SelectMethod=cursor;integratedSecurity=true",props);
//perform db actions here
Thread.currentThread().setContextClassLoader(currentClassLoader);
unloadDLL("sqljdbc_auth.dll",loader);
}
private synchronized static void unloadDllFile(String dllName,ClassLoader classLoader) throws Throwable {
try {
    Field field = ClassLoader.class.getDeclaredField("nativeLibraries");
    field.setAccessible(true);
    Map<Object,Object> lib = (ConcurrentHashMap<Object,Object>) field.get(classLoader);
    Set<Object> keyset = lib.keySet();
    for (Object dllpath : keyset) {
        if (dllpath.toString().contains(dllName)) {                    
            Object o = lib.get(dllpath);                    
            classLoader = null;
            field = null;
            lib.remove(dllpath);                     
            keyset.remove(dllpath);                   
            o = null;
            System.gc();                   
        }
     } 
  } catch (Exception e) {
        System.out.println("Exception in dll is "+e.getMessage());
         
  }
}

第二个组件中有一个类似的代码,但是它在那里引发了异常。 加载第二个组件时的异常stacktrace是:

com.microsoft.sqlserver.jdbc.sqlServerException: This driver is not configured for integrated authentication. ClientConnectionId:d19de7a1-d099-477c-9c18-0c4cd5807f5e
at com.microsoft.sqlserver.jdbc.sqlServerConnection.terminate(sqlServerConnection.java:2892)
at com.microsoft.sqlserver.jdbc.AuthenticationJNI.<init>(AuthenticationJNI.java:72)
at com.microsoft.sqlserver.jdbc.sqlServerConnection.logon(sqlServerConnection.java:3636)
at com.microsoft.sqlserver.jdbc.sqlServerConnection$logonCommand.doExecute(sqlServerConnection.java:3627)
at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7194)
at com.microsoft.sqlserver.jdbc.sqlServerConnection.executeCommand(sqlServerConnection.java:2935)
at com.microsoft.sqlserver.jdbc.sqlServerConnection.connectHelper(sqlServerConnection.java:2456)
at com.microsoft.sqlserver.jdbc.sqlServerConnection.login(sqlServerConnection.java:2103)
at com.microsoft.sqlserver.jdbc.sqlServerConnection.connectInternal(sqlServerConnection.java:1950)
at com.microsoft.sqlserver.jdbc.sqlServerConnection.connect(sqlServerConnection.java:1162)
at com.microsoft.sqlserver.jdbc.sqlServerDriver.connect(sqlServerDriver.java:735)
at sample.java_samples.Sample2.loadFile(Sample2.java:66)
at sample.java_samples.Sample2.main(Sample2.java:23)
Caused by: java.lang.UnsatisfiedLinkError: Native Library C:\Windows\System32\sqljdbc_auth.dll already loaded in another classloader
at java.base/java.lang.classLoader$NativeLibrary.loadLibrary(ClassLoader.java:2456)
at java.base/java.lang.classLoader.loadLibrary0(ClassLoader.java:2684)
at java.base/java.lang.classLoader.loadLibrary(ClassLoader.java:2649)
at java.base/java.lang.Runtime.loadLibrary0(Runtime.java:829)
at java.base/java.lang.System.loadLibrary(System.java:1867)
at com.microsoft.sqlserver.jdbc.AuthenticationJNI.<clinit>(AuthenticationJNI.java:52)
at com.microsoft.sqlserver.jdbc.sqlServerConnection.logon(sqlServerConnection.java:3635)
... 10 more

谢谢

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)