maven项目中使用opencv打包jar及依赖jar为独立lib目录相关问题小记
 2018-08-17 15:23:25   1170   0   

本文最后更新于天前,文中介绍内容及环境可能已不适用.请谨慎参考.

项目里面使用的opencv测试可用,最后输出打包却不可用,另外为了不配置环境变量做了很多工作,

此文记录下全部过程发生的问题及解决方法.

 

一. maven依赖本地jar包

maven导入本地jar,基本有下面两种方法

1.1本地jar包安装到maven库

mvn install:install-file -Dfile=D:/opencv-341.jar -DgroupId=com.opencv -DartifactId=opencv-java -Dversion=3.4.1 -Dpackaging=jar

这样在pom里面正常引用就可以.

 

	<dependency>
			<groupId>com.opencv</groupId>
			<artifactId>opencv-java</artifactId>
			<version>3.4.1</version>
	</dependency>


如果不想安装到本地,或者不想项目组每个人都这样安装一遍可以使用下面第二种

 

1.2本地jar包system引入

直接引入项目lib目录的文件,即插即用.

	<dependency>
			<groupId>com.opencv</groupId>
			<artifactId>opencv-java</artifactId>
			<version>3.4.1</version>
	        <scope>system</scope>
			<systemPath>${project.basedir}/lib/opencv-341.jar</systemPath>
	</dependency>
		

这样使用,本地eclipse里面运行是没有问题的.

二. opencv dll/so文件jar使用

2.1 正常环境变量使用

因为opencv最后需要dll或者so本地功能的支持。

代码里面一般是这样。不管是什么系统,配置上环境变量即可自动加载dll或者so

# System.loadLibrary("opencv_java341")
 System.loadLibrary(Core.NATIVE_LIBRARY_NAME)

人懒没办法,为了方便部署,减少其他人的部署工作,生成的jar直接能用,折腾了下.

想来动态加载,这样不需要修改环境变量,也不需要添加jar至本地库

2.2 动态加载路径

先把dll和so都打包进项目生成的jar中,在系统启动时,根据系统类型将dll或者so读取释放到指定目录,

然后使用System.load(nativepath);动态加载释放出来的dll或者so

String osName = System.getProperty("os.name");
		boolean iswindow = true;
		String nativename = PropertiesUtil.getProperty("opencv.dll.path");
		if (osName.toLowerCase(new Locale("", "", "")).startsWith("windows")) {
			iswindow = true;
		} else {
			iswindow = false;
			nativename = PropertiesUtil.getProperty("opencv.so.path");
		}

//这里不能用File.separator ... windows下又坑了一回- -!
	    InputStream nativeStream = OpencvHelper.class.getClassLoader().getResourceAsStream("nativelib/"+nativename);

		String path = System.getProperty("user.dir");
		String nativepath =path +  File.separator+ "lib" +File.separator+ nativename;
		File f = new File(path +File.separator+ "lib");
		if (!f.exists())
			f.mkdirs();
		BufferedInputStream reader = null;
		FileOutputStream fo = null;
		try {

			File filenative = new File(nativepath);
			fo = new FileOutputStream(filenative);

			reader = new BufferedInputStream(nativeStream);

			byte[] buffer = new byte[1024];

			while (reader.read(buffer) > 0) {
				fo.write(buffer);
				buffer = new byte[1024];
			}
			
			filenative.deleteOnExit();

		} catch (Exception e) {
			System.err.println("opencv load failed!");
		} finally {
			try {
				if (nativeStream != null)

					nativeStream.close();
				if (fo != null)
					fo.close();
			} catch (Exception e) {

			}
		}

		System.load(nativepath);

2.3 将dll/so文件打包放入jar的相关问题

其中dll放在根目录的nativelib目录,

使用maven打包,将其打入jar包中.

其中filter不要使用,不然会出现问题,filter会将打包的dll文件改变.

开始使用时启用了filter,发现54M的jar最后解析出来变成了72M.导致系统无法加载.

fiterh还是比较好用的:

fiter使用时会方便配置文件的处理,比如配置文件jdbc.properties中使用jdbc.server=@jdbc.server@

在pom中可以配置不同的配置文件来动态替换 jdbc.server的值

<profiles>
		<!-- 初始化数据库 -->
		<profile>
			<id>dev</id>
			<!--可本地修改,避免影响其他开发-->
			<properties>
				  <!--数据库连接-->
                <jdbc.server>192.168.100.134:3306/test</jdbc.server>
                <jdbc.username>test</jdbc.username>

 

如下在pom.xml中打包包含dll/so文件. 

<build>
<resources>
      <resource>
				<targetPath>${project.build.directory}/classes/nativelib</targetPath>
				<directory>nativelib</directory> 
                <!-- 这个filter不能使用,maven好像会导致dll或者so文件发生变化而不能使用     -->
			 	<!-- <filtering>true</filtering>  -->
				<includes>
					<!-- opencv native lib -->
					<include>**/*.dll</include>
					<include>**/*.so</include>
				</includes>
			</resource>
<resources>

...

</build>

三.maven项目打包-spring mvc,lib独立

默认会打包成一个jar包。

3.1 打包jar和依赖分开

将依赖jar包放入单独的lib目录,class独立打包.

	<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<configuration>
					<classesDirectory>${project.build.directory}/classes</classesDirectory>
					<archive>
						<manifest>
							<mainClass>com.alibaba.dubbo.container.Main</mainClass>
							<!-- 打包时 MANIFEST.MF文件不记录的时间戳版本 -->
							<useUniqueVersions>false</useUniqueVersions>
							<addClasspath>true</addClasspath>
							<classpathPrefix>lib/</classpathPrefix>
						</manifest>
                    </archive>
                 </configuration>
            </plugin>


			<!-- 把依赖的jar包,打成一个lib文件夹 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<executions>
					<execution>
						<id>copy-dependencies</id>
						<phase>package</phase>
						<goals>
							<goal>copy-dependencies</goal>
						</goals>
						<configuration>
							<type>jar</type>
							<includeTypes>jar</includeTypes>
							<outputDirectory>
								${project.build.directory}/lib
							</outputDirectory>
						</configuration>
					</execution>
					
					
				</executions>
			</plugin>

这样正常是没有问题的,但是我们懒啊。。前文使用了 system模式的引入。

这种系统引入在最后打包的时候是不会自动导出依赖的-_-!,及前面提到的opencv-java.jar包是不会导出到Lib目录的,

这回导致最后生成的jar找不到opencv相关class而无法运行

 <scope>system</scope>
			<systemPath>${project.basedir}/lib/opencv-341.jar</systemPath>

3.2 依赖的system包没有导出至lib目录

既然不能自动导出,那我们就手动来吧。。

手动复制至打包的lib目录.

<!-- 复制本地jar opencv 库 -->
			 <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>3.1.0</version>
        <executions>
          <execution>
            <id>copy-resources</id>
            <!-- here the phase you need -->
            <phase>package</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/lib</outputDirectory>
              <resources>          
                <resource>
                  <directory>${project.basedir}/lib</directory>
                 	<include>**/*.jar</include>
                
                </resource>
              </resources>              
            </configuration>            
          </execution>
        </executions>
      </plugin>

然而最后还是无法运行~~

 

3.3 依赖的system包写入MANIFEST.MF

这种打包分开的方式,最后也是使用 java -jar xx.jar的方式来运行。

那怎么找依赖jar的呢?

其实是通过目录下的META-INF/MANIFEST.MF文件来找依赖的

这个文件同上也会忽略system引入方式的jar,这就坑爹了。

Manifest-Version: 1.0
Built-By: admin
Class-Path: . lib/opencv-341.jar ...其他jar包,空格分开 
 netty-3.2.6.Final.jar lib/javassist-3.22.0-GA.jar
Build-Jdk: 1.8.0_161
Created-By: Maven Integration for Eclipse
Main-Class: com.alibaba.dubbo.container.Main

既然不引,我们自己来引好了,

修改打包插件配置增加jar包的MF文件引入

	<!-- 打包jar文件时,配置manifest文件,加入lib包的jar依赖 -->
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<configuration>
					<classesDirectory>${project.build.directory}/classes</classesDirectory>
					<archive>
						<manifest>
							<mainClass>com.alibaba.dubbo.container.Main</mainClass>
							<!-- 打包时 MANIFEST.MF文件不记录的时间戳版本 -->
							<useUniqueVersions>false</useUniqueVersions>
							<addClasspath>true</addClasspath>
							<classpathPrefix>lib/</classpathPrefix>
						</manifest>
						
						<!-- 添加classpath缺少的内容-->
						<manifestEntries>
							<Class-Path>. lib/opencv-341.jar lib/xxx.jar</Class-Path>
						</manifestEntries>
							
					</archive>
					<excludes>
						<exclude>log4j2-test.xml</exclude>
					</excludes>
				</configuration>
				

			</plugin>

这样就ok了!

 

四.springboot环境

上面说的是普通spring mvc,打包,同时lib作为独立目录的方法,

如果系统使用springboot集成打包,则如下处理。这个更简单一点

部分操作时一样的。

打包dll.so

	<resource>
				<targetPath>${project.build.directory}/classes/nativelib</targetPath>
				<directory>nativelib</directory>
				<!-- <filtering>true</filtering> -->
				<includes>
					<!-- opencv native lib -->
					<include>**/*.dll</include>
					<include>**/*.so</include>
					<include>tess4j/**</include>

				</includes>
			</resource>

 

本地sys-lib打包入jar

类似spring mvc ,

springboot的jar包目录再 BOOT-INF/lib下,这里手动copy就好

<!--  spring boot-lib目录 -->
			<resource>
				<targetPath>BOOT-INF/lib/</targetPath>
				<directory>${basedir}/lib</directory>
				<!-- <filtering>true</filtering> -->
				<includes>
					<!-- opencv native lib -->
					<include>**/*.jar</include>
				</includes>
			</resource>

 

 

 

五.linux环境GCC启动

都搞定了,要在各个系统跑一下呢.

在本地windos启动,妥妥的ok。

在ubuntu16.04上跑了下发现正常启动,ok~

然后再center os7 上发现运行不了!

报错:Caused by: java.lang.UnsatisfiedLinkError: /media/sf_vmshare/libopencv_java341.so: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by /media/sf_vmshare/libopencv_java341.so

 

搜索一番,发现是GCC的问题。

这个使用的so是我在ubuntu上编译出来的,

ubuntu上的gcc版本是gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.4) 

而本地center os7上是gcc version 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC) 

编译的高版本在低版本上无法运行。。。这就是编译的坑了。

本来想着怎么升级center os7上的gcc版本了,但是转念一想,为嘛不在低版本呢的gcc上编译一次呢。

 

点击opencv linux so编译相关教程查看如果编译

然后重新编译一次so,在center OS7上使用低版本gcc。

然后就ok了,这样编译出来的so在高版本gcc的ubuntu上也能正常运行。

 

这样运行过程会解压出dll或者so文件,动态加载然后运行!

-----------------

 

坑爹,最后还是出问题了。。妈蛋两个不同的so文件搞混了,外地同事svn更新下来跑不起来,还来了个加班。。

哎,还是不够仔细,后面得加强!

 


 2019-03-21 16:48:38 
 1

  本文基于CC BY-NC-ND 4.0 许可协议发布,作者:野生的喵喵 固定链接: 【maven项目中使用opencv打包jar及依赖jar为独立lib目录相关问题小记】 转载请注明



发表新的评论
{{s_uid}}   , 欢迎回来.
您的称呼(*必填):
您的邮箱地址(*必填,您的邮箱地址不会公开,仅作为有回复后的消息通知手段):
您的站点地址(选填):
留言:

∑( ° △ °|||)︴

(๑•̀ㅂ•́)و✧
<( ̄) ̄)>
[]~( ̄▽ ̄)~*
( ̄ˇ ̄)
[]~( ̄▽ ̄)~*
( ̄ˇ ̄)
╮( ̄▽ ̄)╭
( ̄ε(# ̄)
(⊙ˍ⊙)
( ̄▽ ̄)~*
∑( ° △ °|||)︴

文章分类

可能喜欢 

KxのBook@Copyright 2017- All Rights Reserved
Designed and themed by 野生的喵喵   1621556   44913