踩过了很多的坑,查了很多资料,在此记录一下,以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)的更多相关文章

  1. 【java-console】如何双击运行可执行jar包及遇到依赖dll报错问题的解决办法

    如何配置双击运行可执行jar包的步骤,请移步到   这里   查看具体的操作,此处不再介绍. 本文主要解决如何处理依赖dll报错的问题解决办法. 我有一个jar包可执行文件运行需要依赖第三方的dll文 ...

  2. Jar包转成Dll的方式(带嵌套的jar也能做) (转)

    研究很好几天,终于成功了.因为写了一个Java的项目,现在要求要改写成C#版本的.但是其中用到了svnkit,svnkit是java平台的.改写成C#的话,要使用SharpSVN,但是SharpSVN ...

  3. Jar包转成Dll的方式(带嵌套的jar也能做)

    研究很好几天,终于成功了.因为写了一个Java的项目,现在要求要改写成C#版本的.但是其中用到了svnkit,svnkit是java平台的.改写成C#的话,要使用SharpSVN,但是SharpSVN ...

  4. SpringBoot+Maven多模块项目(创建、依赖、打包可执行jar包部署测试)完整流程

    一,创建Maven多模块项目先建立外层父工程         File →new →project  选择Spring Initializr          Next下一步到以下页面 工程结构如下 ...

  5. JAVA生成(可执行)Jar包的全面详解说明 [打包][SpringBoot][Eclipse][IDEA][Maven][Gradle][分离][可执行]

    辛苦所得,转载还请注明: https://www.cnblogs.com/applerosa/p/9739007.html  得空整理了关于java 开发中,所有打包方式的 一个操作方法, 有基于ID ...

  6. eclipse导出maven工程的可执行jar包

    一.eclipse导出maven工程的可执行jar包 建立两个maven工程 ZKServer 和ZKClient 注意:用maven进行开发管理的话,默认的打出来的jar包是不能运行的,需要在pom ...

  7. IDEA 直接点击运行执行正常,命令行下面执行Jar包出现部分乱码的情况。

    解决方案如上: 有个Springboot项目为了测试方便,模型类用中文作为字段属性,封装成Odata格式,在通过Springboot发布并打成jar包. 通过命令行启动jar包里面的Springweb ...

  8. Spring Boot可执行Jar包运行原理

    目录 1. 打可执行Jar包 2. 可执行Jar包内部结构 3. JarLauncher 4. 简单总结 5. 远程调试 Spring Boot有一个很方便的功能就是可以将应用打成可执行的Jar.那么 ...

  9. Unity通过Jar包调用Android

    Unity通过Jar包调用Android 我们会需要面对下面几个问题,我们一个一个来解决: 怎样在Android Studio中打Jar包 怎样打一个Unity使用的Jar包 怎样在Unity工程中使 ...

随机推荐

  1. pat 团体天梯赛 L2-004. 这是二叉搜索树吗?

    L2-004. 这是二叉搜索树吗? 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 一棵二叉搜索树可被递归地定义为具有下列性质的 ...

  2. [SaltStack] salt-minion启动流程

    SaltStack源码阅读 前面理了下salt-master的启动流程, 这次来看看salt-minion的启动流程. 启动salt-minion方法: /etc/init.d/salt-minion ...

  3. Scrapy笔记:日志的使用

    scrapy的日志记录有两种方式: spider.logger.xx()和python标准库中的logger = logging.get_Logger('log information') 向日志对象 ...

  4. Python Challenge 第十二关

    这一关依旧只有一张图,右键源代码也没有任何注释,也用PIL处理过那张图但没任何头绪,没办法只有上网搜答案. 别人的博客里说,源代码里面图片的名字是 evil1.jpg,那肯定会有 evil2.jpg. ...

  5. A Wasserstein Distance[贪心/模拟]

    链接:https://www.nowcoder.com/acm/contest/91/A来源:牛客网 最近对抗生成网络(GAN)很火,其中有一种变体WGAN,引入了一种新的距离来提高生成图片的质量.这 ...

  6. APACHE 配置虚拟主机和HTTPS

    prepare the running env of os make sure you are using redhat or centen os 7.5 cat /etc/redhat-releas ...

  7. 使用springboot 2.0后,静态资源默认路径无法访问

    原因在于:META-INF/resources / resources / static / public 都是spring boot 认为静态资源应该放置的位置,会自动去寻找静态资源 然而,在2.0 ...

  8. Elasticsearch本地环境安装和常用操作

    本篇文章首发于我的头条号Elasticsearch本地环境安装和常用操作,欢迎关注我的头条号和微信公众号"大数据技术和人工智能"(微信搜索bigdata_ai_tech)获取更多干 ...

  9. 【转】彻底弄懂Java中的equals()方法以及与"=="的区别

    彻底弄懂Java中的equals()方法以及与"=="的区别 一.问题描述:今天在用Java实现需求的时候,发现equals()和“==”的功能傻傻分不清,导致结果产生巨大的偏差. ...

  10. Ruby Time And DateTime之Time in Core

    今天遇到一个问题,就是在Ruby中对于Time和DateTime的使用,不是很明了,现在研究一下: 先说Time: 在Ruby2.0中关于Time有两处定义一个是在Core中,http://www.r ...