背景
在SpringBoot项目中调用虹软SDK,来实现人脸、性别检测等功能。且此项目需要部署到不同环境,包括Windows和Linux。以Windows为例,从下图可见,需要加载本地jar包(maven的公开库找不到此依赖),和native库(Windows上为.dll文件,Linux上为.so文件)。
加载本地jar包
pom.xml中的本地依赖如下。当使用了 system 作用域,Maven 不会尝试从远程仓库下载这个依赖,而是直接使用指定路径的本地文件:
<dependency> <!--虹软 人像识别-->
<groupId>com.arcsoft.face</groupId>
<artifactId>arcsoft-sdk-face</artifactId>
<version>3.0.0.0</version>
<scope>system</scope>
<systemPath>${pom.basedir}/libs/WIN64/arcsoft-sdk-face-3.0.0.0.jar</systemPath>
</dependency>
另外注意需要进行以下设置,不然打jar包时,不会包含system作用域的依赖:
加载native库
可简单通过os.name等系统属性来自动选择不同路径。核心代码:
private static String getLibPath() { //native库路径
String osName = System.getProperty("os.name").toLowerCase();
String localPath = System.getProperty("user.dir");
String libPath = localPath + File.separator + "libs";
if (osName.contains("win")) {
libPath += File.separator + "WIN64";
} else {
libPath += File.separator + "linux";
}
return libPath;
}
@PostConstruct
public void init() {
faceEngine = new FaceEngine(getLibPath());
。。。
从虹软的代码中可以看到,加载native库的底层关键方法是System.load等方法。
打jar包时如何处理native库
处理 native 库(如 DLL 文件) 的几种思路:
方案一:手动复制DLL到JAR外部的指定目录(如应用根目录或系统库路径)
方案二:将dll打进jar包,运行时再提取DLL到临时目录(感觉不如方案三,放弃)
方案三(推荐):使用 Maven 在构建阶段复制 DLL 到外部 lib 目录 。和方案一一样不将native 文件打进jar包,比方案一优秀在复制动作是自动化的。
亲测有效。示例:修改 pom.xml,在<project><build><plugins>
标签中加入:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>copy-native-libs</id>
<phase>process-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<!-- 创建目标目录 -->
<mkdir dir="${project.build.directory}/libs"/>
<!-- 复制 WIN64 目录下的内容 -->
<copy todir="${project.build.directory}/libs/WIN64">
<fileset dir="libs/WIN64"/>
</copy>
</target>
</configuration>
</execution>
</executions>
</plugin>
运行mvn pacakge命令后,可以看到target目录下有了复制过来的文件:
原理(by通义千问):Maven 本身不提供直接复制文件的功能,但可以通过使用 maven-antrun-plugin 插件 来调用 Ant 任务实现文件复制。
根据OS自动选择、或者手动选择加载文件
包括本地jar包和native库。可在pom.xml文件中使用profile标签,亲测有效:
其中 <activation> <os> <family>windows</family> </os> </activation>
表示当操作系统是 Windows 时,此 Profile 将被自动激活。此Profile还配置了要包含的本地依赖,和mvn package时要复制的native库,具体内容都在前面介绍过了。
构建项目时既可以自动激活Profile,也可以直接指定Profile。比如指定ID为win的profile: mvn package -Pwin
:
但要注意一点:
各Profile之间没有互斥关系
这意味着当在windows环境下运行mvn package -Plinux, 不仅Profile linux会运行,Profile win也会因为它的activation标签满足OS条件而自动运行。这时可以加一个参数!
: mvn package -Plinux -P!win , 明确表示不运行Profile win