可执行Jar包调用动态链接库(DLL/SO)
踩过了很多的坑,查了很多资料,在此记录一下,以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!!!");
} } }
可执行Jar包调用动态链接库(DLL/SO)的更多相关文章
- 【java-console】如何双击运行可执行jar包及遇到依赖dll报错问题的解决办法
如何配置双击运行可执行jar包的步骤,请移步到 这里 查看具体的操作,此处不再介绍. 本文主要解决如何处理依赖dll报错的问题解决办法. 我有一个jar包可执行文件运行需要依赖第三方的dll文 ...
- Jar包转成Dll的方式(带嵌套的jar也能做) (转)
研究很好几天,终于成功了.因为写了一个Java的项目,现在要求要改写成C#版本的.但是其中用到了svnkit,svnkit是java平台的.改写成C#的话,要使用SharpSVN,但是SharpSVN ...
- Jar包转成Dll的方式(带嵌套的jar也能做)
研究很好几天,终于成功了.因为写了一个Java的项目,现在要求要改写成C#版本的.但是其中用到了svnkit,svnkit是java平台的.改写成C#的话,要使用SharpSVN,但是SharpSVN ...
- SpringBoot+Maven多模块项目(创建、依赖、打包可执行jar包部署测试)完整流程
一,创建Maven多模块项目先建立外层父工程 File →new →project 选择Spring Initializr Next下一步到以下页面 工程结构如下 ...
- JAVA生成(可执行)Jar包的全面详解说明 [打包][SpringBoot][Eclipse][IDEA][Maven][Gradle][分离][可执行]
辛苦所得,转载还请注明: https://www.cnblogs.com/applerosa/p/9739007.html 得空整理了关于java 开发中,所有打包方式的 一个操作方法, 有基于ID ...
- eclipse导出maven工程的可执行jar包
一.eclipse导出maven工程的可执行jar包 建立两个maven工程 ZKServer 和ZKClient 注意:用maven进行开发管理的话,默认的打出来的jar包是不能运行的,需要在pom ...
- IDEA 直接点击运行执行正常,命令行下面执行Jar包出现部分乱码的情况。
解决方案如上: 有个Springboot项目为了测试方便,模型类用中文作为字段属性,封装成Odata格式,在通过Springboot发布并打成jar包. 通过命令行启动jar包里面的Springweb ...
- Spring Boot可执行Jar包运行原理
目录 1. 打可执行Jar包 2. 可执行Jar包内部结构 3. JarLauncher 4. 简单总结 5. 远程调试 Spring Boot有一个很方便的功能就是可以将应用打成可执行的Jar.那么 ...
- Unity通过Jar包调用Android
Unity通过Jar包调用Android 我们会需要面对下面几个问题,我们一个一个来解决: 怎样在Android Studio中打Jar包 怎样打一个Unity使用的Jar包 怎样在Unity工程中使 ...
随机推荐
- jsonp 格式
jQuery(document).ready(function(){ $.ajax({ type: "get", async: false, url: "http://f ...
- Named Formats!
原文发布时间为:2011-06-26 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Text;using System.Web;using Sys ...
- t4 template multi file output
1.Manager.ttinclude <#@ assembly name="System.Core"#> <#@ assembly name="Sys ...
- VS Code开发技巧集锦【转】
转自:http://blog.csdn.net/tiantangyouzui/article/details/52163175 入门 自定义 扩展 文件/文件夹管理 编辑技巧 智能感应功能 代码片段 ...
- 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---6
以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下: <Linux命令行与shell脚本 ...
- Ubuntu 14.04 x64配置Android 4.4 kitkat编译环境的方法
Ubuntu 14.04 x64配置Android 4.4 kitkat编译环境的方法跟Ubuntu 12.04 - 13.10 以及jellybean编译环境配置没多大区别, 顺便记录下而已: Ub ...
- Spring Boot学习——Controller的使用
本文主要记录几个注释的使用方法. 1. @Controller : 处理http请求 2. @RequestMapping : 配置URL映射 3. @RestController : 组合注解,sp ...
- git的使用学习(九)搭建git服务器
搭建Git服务器 在远程仓库一节中,我们讲了远程仓库实际上和本地仓库没啥不同,纯粹为了7x24小时开机并交换大家的修改. GitHub就是一个免费托管开源代码的远程仓库.但是对于某些视源代码如生命的商 ...
- hdu 1385(Floyed+打印路径好题)
Minimum Transport Cost Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/O ...
- failed to obtain a cell from its dataSource 问题处理
最近在处理bugly问题的时候,总会看到回话列表有奔溃,但是由于没有啥具体的细节原因也无从下手. 只知道ConversationListViewController这个类的奔溃,报的问题是这个,也只有 ...