spring boot jar包启动JNI相对路径加载dll方案二
Posted 洛阳泰山
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring boot jar包启动JNI相对路径加载dll方案二相关的知识,希望对你有一定的参考价值。
前言
在java调用dll的项目中,之间的部署的方式,是需要手动提前将所需的dll,替换放在jdkbin文件夹或者C:\\Windows\\System32文件夹的下,后续开发的过程中,dll文件需要不断更新,一方面dll版本维护成为比较麻烦的事情,还有部署方式略显繁琐,经过一段的摸索后,在项目jar包启动的时候实现dll自动部署的方案。
原理
JNI的加载方式分为两种一种是动态加载就是在JDKbin文件或者\\System32文件夹的下,寻找dll加载,一种是利用绝对路径去加载,之前利用绝对路径去加载的时候,会遇到一个问题,因为dll在jar包里面,获取的绝对路径中间都会包含“XXX.jar!”,导致dll加载失败,想到的思路是,在项目启动的时候,自动将dll输出到jar所在的同级目录下,然后再根据新输出dll的绝对路径去加载即可。
项目中dll的位置,之前方案一《spring boot jar包启动,JNI相对路径加载dll方案一》,dll实在resources下,dll文件打入到了jar包中,然后启动时候把dll文件复制到了jar包的同级目录,进行加载的。此方案,因为设计到多套dll文件,且dll文件过大,dll的更新的频率很小,每次打包部署太浪费时间,所以,不打包到jar里,部署时候需要手动放在jar的同级目录。
核心代码示例
创建 JniUtil工具类只负责加载和卸载dll。可以实现多了dll入口文件的灵活加载和卸载,代码如下,创建JniUtil 类,复制粘贴即可( @PostConstruct 注解是项目启动时候就执行方法,代码中启动加载了dll_1,根据自己的需求设置,启动加载)
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Vector;
@Component
@Slf4j
public class JniUtil {
@PostConstruct
public static void loadDll_1() {
loadDLL("dll_1", "auoLoad.dll");
}
public static void loadDll_2() {
loadDLL("dll_2", "projectForJava.dll");
}
public static void unloadDll_1() { unloadDLL("auoLoad.dll"); }
public static void unloadDll_2() {
unloadDLL("projectForJava.dll");
}
private synchronized static void loadDLL(String folderName, String libName) {
String classPath = new JniUtil().getClass().getResource("/").getPath();
if (classPath.indexOf(".jar") > 0) {
classPath = classPath.substring(0, classPath.lastIndexOf(".jar"));
classPath = classPath.substring(6, classPath.lastIndexOf("/"));
String dllPath = File.separator + classPath + "/" + folderName;
log.info("========dll加载路径:" + dllPath + "========");
System.load(dllPath + "/" + libName);
} else {
String projectPath = classPath.replace("target/classes/", "");
String dllPath = projectPath + folderName + "/" + libName;
log.info("========dll加载路径:" + dllPath + "========");
}
log.info("========dll加载成功========");
}
public synchronized static void unloadDLL(String libName) {
try {
ClassLoader classLoader = JniUtil.class.getClassLoader();
Field field = ClassLoader.class.getDeclaredField("nativeLibraries");
field.setAccessible(true);
Vector<Object> libs = (Vector<Object>) field.get(classLoader);
Iterator it = libs.iterator();
while (it.hasNext()) {
Object object = it.next();
Field[] fs = object.getClass().getDeclaredFields();
for (int k = 0; k < fs.length; k++) {
if (fs[k].getName().equals("name")) {
fs[k].setAccessible(true);
String dllPath = fs[k].get(object).toString();
if (dllPath.endsWith(libName)) {
Method finalize = object.getClass()
.getDeclaredMethod("finalize");
finalize.setAccessible(true);
finalize.invoke(object);
}
}
}
}
log.info("========dll卸载成功========");
} catch (Throwable th) {
log.error("========dll卸载失败========");
th.printStackTrace();
}
}
}
jni接口代码如下
package com.hxtx.stripmine.jni;
import org.springframework.stereotype.Component;
/**
*
* JNI调用dll方法
*
* @since JDK1.8
* @author tarzan Liu
* @date 2021年04月01日 14:37:43
*/
@Component
public class GraphicJNIService {
/**
* 方法描述: 解析dem材质边界
*
* @param fileUrl (dwg文件地址)
* @Return {@link String}
* @author tarzan Liu
* @date 2021年04月01日 14:38:05
*/
public native String parseLayer(String fileUrl);
/**
* 方法描述: dwg文件编译1
*
* @param tempFolder 中间文件文件夹绝对路径
* @param dwgFolder 所需材料文件夹绝对路径
* @param materialInfo 当前启用的地形材质配置信息
* @param netWorkJsonPath 生成的路网json文件绝对路径
* @param elevationJsonPath 生成的高程json文件绝对路径
* @param x: 438000, y: 4964000 北京54参照点
* @param flag 编译类型:1两者都编译 2只编译路网(只生成路网json,不再调用韩总dll)
* @Return {@link String}
* @author tarzan Liu
* @date 2021年04月01日 14:39:43
*/
public native String compileDWG(String tempFolder,String dwgFolder,String materialInfo,String netWorkJsonPath,String elevationJsonPath,double x,double y,int flag);
/**
* 方法描述: dwg文件编译2
*
* @param tempFolder 中间文件文件夹绝对路径
* @param resultFolder 成果文件夹绝对路径
* @param x,y compileDWG()方法返回的x,y
* @param lng,lat 经纬度参照点
* @Return {@link String}
* @author tarzan Liu
* @date 2021年04月01日 14:39:43
*/
public native String tranDataToB3dm(String tempFolder, String resultFolder, double lng, double lat, double x, double y, double heigh);
}
项目Service类中如何调用,示例代码如下
@Resource
private GraphicJNIService graphicJNIService;
@Transactional(rollbackFor = Throwable.class)
public void compileDemDwg(){
JniUtil.loadDll_2();
//省略部分代码
graphicJNIService.tranDataToB3dm(tempFolder,demJsonPath,89.21598146531036,44.808601928195955,x,y,0);
JniUtil.unloadDll_2();
} catch (Exception e) {
e.printStackTrace();
}
}
以上是关于spring boot jar包启动JNI相对路径加载dll方案二的主要内容,如果未能解决你的问题,请参考以下文章
spring boot 打jar包,获取resource路径下的文件