springboot本地调试没问题,打包运行报错原因及分析
作者:yuanshiren133
这篇文章主要介绍了springboot本地调试没问题,打包运行报错原因及分析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
springboot本地调试没问题,打包运行报错原因分析
如果引用了本地jar包或者so库
.dll库等文件,需要在打包的时候都加载进去。
如下图:本地正常,打包的时候谨记,需要打包进去,怎么验证是否打包成功呢?我们继续看打包后的图片。
把jar包后缀改成zip 格式的,打开压缩文件,框内路径,查看libs下的包是否在里面可以找到。
如果可以找到就是打包进去了,找不到的话,就是没打包进去,稍后我们再说怎么打包进去。
动态库也打包进去了。
动态库打包进去方式如下
import org.opencv.core.Core; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author Arthur.yu * @date 2021/12/8 0008 */ @Configuration public class NativeConfig { static { } @Bean public void loadLib() { //根据操作系统判断,如果是linux系统则加载c++方法库 String systemType = System.getProperty("os.name"); String ext = (systemType.toLowerCase().indexOf("win") != -1) ? ".dll" : ".so"; // if (ext.equals(".so")) { try { NativeLoader.loader("native"); } catch (Exception e) { System.out.println("加载so库失败"); } // }else { // System.out.println("load --- dll === sucess"); // } System.out.println("loaded"); } }
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 Arthur.yu * @date 2021/12/8 0008 */ 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.out.println("path :" + tempFile.getPath()); System.load(tempFile.getPath()); System.out.println("加载native文件 :" + tempFile + "成功!!"); } catch (UnsatisfiedLinkError e) { System.out.println("加载native文件 :" + tempFile + "失败!!请确认操作系统是X86还是X64!!!"); } } }
运行的时候,会在jar包所在目录生成一个native文件夹,里面放的就是动态库
下面我们看一下本地jar包怎么打进去
jar包存放路径
pom 文件引用一下
<dependency> <groupId>org.opencv</groupId> <artifactId>opencv</artifactId> <version>0.0.1</version> <scope>system</scope> <systemPath>${project.basedir}/libs/opencv-343.jar</systemPath> </dependency>
pom打包配置
<build> <plugins> <!--参考文章:https://blog.csdn.net/liupeifeng3514/article/details/80236077--> <plugin> <!-- 指定maven编译的jdk版本,如果不指定,maven3默认用jdk 1.5 maven2默认用jdk1.3 --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <!-- 源代码使用的JDK版本 --> <source>1.8</source> <!-- 需要生成的目标class文件的编译版本 --> <target>1.8</target> <!-- 字符集编码 --> <encoding>UTF-8</encoding> <!-- 跳过测试 --> <skip>true</skip> <compilerArguments> <extdirs>${project.basedir}/libs</extdirs> </compilerArguments> </configuration> </plugin> </plugins> <resources> <resource> <directory>${project.basedir}/libs/</directory> <targetPath>BOOT-INF\lib</targetPath> <includes> <include>**/*.jar</include> </includes> </resource> <resource> <directory>${project.basedir}/libs</directory> </resource> </resources> </build>
好了。动态库跟jar包都打包进去了。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。