踩過了很多的坑,查了很多資料,在此記錄一下,以SpringBoot項目為基礎。
Maven加入JNA依賴
<!-- JNA start --> <dependency> <groupId>com.sun.jna</groupId> <artifactId>jna</artifactId> </dependency> <!-- JNA end -->
動態鏈接庫放在classpath下的natives文件夾下
主入口中的代碼
@ServletComponentScan @SpringBootApplication @ComponentScan("com.yunzhitx.sdy") @MapperScan(basePackages = "com.yunzhitx.sdy.core.**.infra") public class TaskApplication { @Bean public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { //加載動態鏈接庫,注意和SpringBoot的啟動 String systemType = System.getProperty("os.name"); if (systemType.toLowerCase().indexOf("win") != -1) loadNative("dhnetsdk"); else loadNative("libdhnetsdk"); SpringApplication.run(TaskApplication.class); } private synchronized static void loadNative(String nativeName) { String systemType = System.getProperty("os.name"); String fileExt = (systemType.toLowerCase().indexOf("win") != -1) ? ".dll" : ".so"; // String sysUserTempDir = System.getProperty("java.io.tmpdir"); /*String javaLibraryPath = System.getProperty("java.library.path"); String sysUserTempDir = "" ; if(systemType.toLowerCase().indexOf("win") != -1) { String[] dirs = javaLibraryPath.split(";");//分號 sysUserTempDir = dirs[0]; }else { String[] dirs = javaLibraryPath.split(":"); //冒號 sysUserTempDir = dirs[0]; }*/ File path = new File("."); //將所有動態鏈接庫dll/so文件都放在一個臨時文件夾下,然后進行加載 //這是應為項目為可執行jar文件的時候不能很方便的掃描里面文件 //此目錄放置在與項目同目錄下的natives文件夾下 String sysUserTempDir = path.getAbsoluteFile().getParent() + File.separator + "natives"; System.out.println("------>>native lib臨時存放目錄 : " + sysUserTempDir); String fileName = nativeName + fileExt; InputStream in = null; BufferedInputStream reader = null; FileOutputStream writer = null; File tempFile = new File(sysUserTempDir + File.separator + fileName); if(!tempFile.getParentFile().exists()) tempFile.getParentFile().mkdirs() ; if (tempFile.exists()) { tempFile.delete(); } try { //讀取文件形成輸入流 in = TaskApplication.class.getResourceAsStream("/native/" + fileName); if (in == null) in = TaskApplication.class.getResourceAsStream("native/" + fileName); TaskApplication.class.getResource(fileName); reader = new BufferedInputStream(in); writer = new FileOutputStream(tempFile); byte[] buffer = new byte[1024]; while (reader.read(buffer) > 0) { writer.write(buffer); buffer = new byte[1024]; } } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) in.close(); if (writer != null) writer.close(); } catch (IOException e) { e.printStackTrace(); } } System.load(tempFile.getPath()); System.out.println("------>> 加載native文件 :" + tempFile + "成功!!"); } }
主入口函數的代碼主要是進行加載操作,當然也可以在需要使用到的地方在進行加載。
加載的時候進行了如下操作,1、將所有動態鏈接庫dll/so文件都放在一個臨時文件夾下。2、讀取臨時文件IO流進行加載。
這是應為項目為可執行jar文件的時候不能很方便的掃描里面文件
此目錄代碼放置在與項目同目錄下的natives文件夾下。
在通過編寫好的接口類進行實例化操作:
NetSDKLib monitorNetSdk = (NetSDKLib) Native.loadLibrary("dhnetsdk", NetSDKLib.class);
Linux系統下,需要將放置dll/so文件的文件夾加入到環境變量中,否則依然會提示找不到文件的錯誤:
export LD_LIBRARY_PATH=/home/sdy_task/natives
但是這種方式是臨時性的,一旦重啟就將失效,所有建議寫入配置文件中:
修改/etc/profile,添加如下代碼
LD_LIBRARY_PATH=/home/sdy_task/natives
export LD_LIBRARY_PATH
升級版
package org.yoki.edu.image.utils; import java.io.*; import java.net.JarURLConnection; import java.net.URL; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; /** * @author Sky$ * @Description: TODO * @date 2018/2/8$ 17:55$ */ public class NativeLoader { /** * 加載項目下的native文件,DLL或SO * * @param dirPath 需要掃描的文件路徑,項目下的相對路徑 * @throws IOException * @throws ClassNotFoundException */ public synchronized static void loader(String dirPath) throws IOException, ClassNotFoundException { Enumeration<URL> dir = Thread.currentThread().getContextClassLoader().getResources(dirPath); // 獲取操作系統類型 String systemType = System.getProperty("os.name"); String systemArch = System.getProperty("os.arch"); // 獲取動態鏈接庫后綴名 String ext = (systemType.toLowerCase().indexOf("win") != -1) ? ".dll" : ".so"; while (dir.hasMoreElements()) { URL url = dir.nextElement(); String protocol = url.getProtocol(); if ("jar".equals(protocol)) { JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection(); JarFile jarFile = jarURLConnection.getJarFile(); // 遍歷Jar包 Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry jarEntry = entries.nextElement(); String entityName = jarEntry.getName(); if (jarEntry.isDirectory() || !entityName.startsWith(dirPath)) { continue; } if (entityName.endsWith(ext)) { loadJarNative(jarEntry); } } } else if ("file".equals(protocol)) { File file = new File(url.getPath()); loadFileNative(file, ext); } } } private static void loadFileNative(File file, String ext) { if (null == file) { return; } if (file.isDirectory()) { File[] files = file.listFiles(); if (null != files) { for (File f : files) { loadFileNative(f, ext); } } } if (file.canRead() && file.getName().endsWith(ext)) { try { System.load(file.getPath()); System.out.println("加載native文件 :" + file + "成功!!"); } catch (UnsatisfiedLinkError e) { System.out.println("加載native文件 :" + file + "失敗!!請確認操作系統是X86還是X64!!!"); } } } /** * @throws IOException * @throws ClassNotFoundException * @Title: scanJ * @Description 掃描Jar包下所有class */ /** * 創建動態鏈接庫緩存文件,然后加載資源文件 * * @param jarEntry * @throws IOException * @throws ClassNotFoundException */ private static void loadJarNative(JarEntry jarEntry) throws IOException, ClassNotFoundException { File path = new File("."); //將所有動態鏈接庫dll/so文件都放在一個臨時文件夾下,然后進行加載 //這是應為項目為可執行jar文件的時候不能很方便的掃描里面文件 //此目錄放置在與項目同目錄下的natives文件夾下 String rootOutputPath = path.getAbsoluteFile().getParent() + File.separator; String entityName = jarEntry.getName(); String fileName = entityName.substring(entityName.lastIndexOf("/") + 1); System.out.println(entityName); System.out.println(fileName); File tempFile = new File(rootOutputPath + File.separator + entityName); // 如果緩存文件路徑不存在,則創建路徑 if (!tempFile.getParentFile().exists()) { tempFile.getParentFile().mkdirs(); } // 如果緩存文件存在,則刪除 if (tempFile.exists()) { tempFile.delete(); } InputStream in = null; BufferedInputStream reader = null; FileOutputStream writer = null; try { //讀取文件形成輸入流 in = NativeLoader.class.getResourceAsStream(entityName); if (in == null) { in = NativeLoader.class.getResourceAsStream("/" + entityName); if (null == in) { return; } } NativeLoader.class.getResource(fileName); reader = new BufferedInputStream(in); writer = new FileOutputStream(tempFile); byte[] buffer = new byte[1024]; while (reader.read(buffer) > 0) { writer.write(buffer); buffer = new byte[1024]; } } catch (IOException e) { e.printStackTrace(); } try { if (in != null) { in.close(); } if (writer != null) { writer.close(); } } catch (IOException e) { e.printStackTrace(); } try { System.load(tempFile.getPath()); System.out.println("加載native文件 :" + tempFile + "成功!!"); } catch (UnsatisfiedLinkError e) { System.out.println("加載native文件 :" + tempFile + "失敗!!請確認操作系統是X86還是X64!!!"); } } }