我正在维护一个需要连接到Microsoft SQL Server实例的Java Swing应用程序。出于各种原因,我选择替换与jTDS一起使用的本机SQL Server驱动程序(前面提到的Microsoft驱动程序当时没有工作,并且在该领域中显然也失败了)。当我尝试在IDE之外运行可执行文件.jar时,我遇到了问题,因为我错过了相应的ntlmauth.dll依赖项。
在继续之前,请务必注意,此应用程序正在极其严格限制(仅限Windows)的环境中开发和使用:
我正在尝试的解决方案是this one和this one to check it的组合 - 基本上将.dll打包在.jar中,然后将其解压缩并在必要时加载它 - 就像大多数我发现的其他解决方案与上述限制不相符;但是,我遇到了一个问题,即使在本机库表面上已经“加载”之后,我也会遇到一个例外,说它不是。
我的启动前代码:
private static final String LIB_BIN = "/lib-bin/";
private static final String JTDS_AUTH = "ntlmauth";
// load required JTDS binaries
static {
logger.info("Attempting to load library {}.dll", JTDS_AUTH);
try {
System.loadLibrary(JTDS_AUTH);
} catch (UnsatisfiedLinkError e) {
loadFromJar();
}
try {
// do some quick checks to make sure that went ok
NativeLibraries nl = new NativeLibraries();
logger.debug("Loaded libraries: {}", nl.getLoadedLibraries().toString());
} catch (NoSuchFieldException ex) {
logger.info("Native library checker load failed", ex);
}
}
/**
* When packaged into JAR extracts DLLs, places these into
*/
private static void loadFromJar() {
// we need to put DLL in temp dir
String path = ***;
loadLib(path, JTDS_AUTH);
}
/**
* Puts library to temp dir and loads to memory
*/
private static void loadLib(String path, String name) {
name = name + ".dll";
try {
// have to use a stream
InputStream in = net.sourceforge.jtds.jdbc.JtdsConnection.class.getResourceAsStream(LIB_BIN + name);
// always write to different location
File fileOut = new File(System.getProperty("java.io.tmpdir") + "/" + path + LIB_BIN + name);
logger.info("Writing dll to: " + fileOut.getAbsolutePath());
OutputStream out = FileUtils.openOutputStream(fileOut);
IOUtils.copy(in, out);
in.close();
out.close();
System.load(fileOut.toString());
} catch (Exception e) {
logger.error("Exception with native library loader", e);
JOptionPane.showMessageDialog(null, "Exception loading native libraries: " + e.getLocalizedMessage(), "Exception", JOptionPane.ERROR_MESSAGE);
}
}
正如您所看到的,我基本上从第一个链接逐字复制了解决方案,只需稍作修改即可尝试运行应用程序。我还从第二个链接复制了该类并将其命名为NativeLibraries,该方法的调用相当无关,但它显示在日志中。
无论如何,这里是启动应用程序时日志输出的相关位:
2015-07-20 12:32:33 INFO - Attempting to load library ntlmauth.dll
2015-07-20 12:32:33 INFO - Writing dll to: C:\Users\***\lib-bin\ntlmauth.dll
2015-07-20 12:32:33 DEBUG - Loaded libraries: [C:\Program Files\Java\jre1.8.0_45\bin\zip.dll, C:\Program Files\Java\jre1.8.0_45\bin\prism_d3d.dll, C:\Program Files\Java\jre1.8.0_45\bin\prism_sw.dll, C:\Program Files\Java\jre1.8.0_45\bin\msvcr100.dll, C:\Program Files\Java\jre1.8.0_45\bin\glass.dll, C:\Program Files\Java\jre1.8.0_45\bin\net.dll, C:\Users\***\lib-bin\ntlmauth.dll]
2015-07-20 12:32:33 INFO - Application startup
***
2015-07-20 12:32:36 ERROR - Database exception
java.sql.SQLException: I/O Error: SSO Failed: Native SSPI library not loaded. Check the java.library.path system property.
at net.sourceforge.jtds.jdbc.TdsCore.login(TdsCore.java:654) ~[jtds-1.3.1.jar:1.3.1]
at net.sourceforge.jtds.jdbc.JtdsConnection.<init>(JtdsConnection.java:371) ~[jtds-1.3.1.jar:1.3.1]
at net.sourceforge.jtds.jdbc.Driver.connect(Driver.java:184) ~[jtds-1.3.1.jar:1.3.1]
at java.sql.DriverManager.getConnection(Unknown Source) ~[na:1.8.0_45]
at java.sql.DriverManager.getConnection(Unknown Source) ~[na:1.8.0_45]
可以看到该库实际上已从日志中的第三行“加载”(如果您不想滚动,则它是最后一个条目)。但是,我只是使用了我觉得可能正在使用本机库的类(我也试过TdsCore类无济于事),因为显示如何执行此操作的示例只是使用了库中包含的随机类。需要。
这里有什么我想念的吗?我对JNI或ClassLoader的内部工作方式不是很熟悉,所以我可能只是错误地加载它。任何建议或建议将不胜感激!
答案 0 :(得分:1)
Welp我想出了一个解决方法:我最终使用了JarClassLoader。这基本上需要将我的所有依赖项(包括Java和本机)复制到&#34;库&#34;我的主.jar中的文件夹,以及在IDE中禁用.jar签名。然后,应用程序由一个新类运行,该类只是创建一个新的JarClassLoader对象并运行&#34; invokeMain&#34;方法 - 一个例子在网站上。经过几天将我的头撞在墙上,整件事花了大约三分钟。
希望有一天能帮到某人!