springboot的可执行fatjar打包部署后,在运行时加载外部jar包;

657 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第31天,点击查看活动详情

配置加载外部依赖jar

项目上需要对接第三方,又不想升级已有jar包,并且现有jar提供了接口,只需要实现相关接口,就能完成对接工作; 这个情况下,使用外部依赖最合适不过;

  • 配置方式

在fatjar(可运行jar)所在目录添加配置文件

loader.properties

在文件中添加配置属性:

loader.path=libs libs为依赖jar所在目录

在同级目录创建文件夹libs,将依赖jar包放入文件夹内,重启服务既可;

  • 以上配置参考官网:

You can add additional locations by setting an environment variable called LOADER_PATH or loader.path in loader.properties (which is a comma-separated list of directories, archives, or directories within archives).


  • 遇到问题

最近在部署一个类似项目时,升级了springboot版本,重新打包后,发现无法加载外部依赖; 使用命令行方式执行,

java -Dloader.path=libs -jar **.jar

同样无法加载依赖包;

通过比对两者不同:

升级前springboot版本为1.5.18.RELEASE 升级后springboot版本为2.3.12.RELEASE

  • 升级前打包方式:
apply plugin: 'spring-boot'

springBoot {
    executable = true
    mainClass = 'com.demo.test'
    layout = 'ZIP'
}
  • 升级后打包方式:
apply plugin: "org.springframework.boot"
apply plugin: "application"

bootJar {
	launchScript()
	mainClassName = 'com.demo.test'
}

springBoot {
	buildInfo()
}

因为看不出问题,卡了好久;

参考官网配置:docs.spring.io/spring-boot…

There are three launcher subclasses (JarLauncher, WarLauncher, and PropertiesLauncher). Their purpose is to load resources (.class files and so on) from nested jar files or war files in directories (as opposed to those explicitly on the classpath). In the case of JarLauncher and WarLauncher, the nested paths are fixed. JarLauncher looks in BOOT-INF/lib/, and WarLauncher looks in WEB-INF/lib/ and WEB-INF/lib-provided/. You can add extra jars in those locations if you want more. The PropertiesLauncher looks in BOOT-INF/lib/ in your application archive by default. You can add additional locations by setting an environment variable called LOADER_PATH or loader.path in loader.properties (which is a comma-separated list of directories, archives, or directories within archives).

上面提示说有三种加载方式,或许是加载方式的不同,导致无法加载外部依赖;

  • 比对两个mainfest.mf文件

原版本MANIFEST.MF

Manifest-Version: 1.0
Start-Class: com.demo.test
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 1.5.18.RELEASE
Implementation-BuildDateTime: Mon Jul 13 15:18:28 CST 2020
Main-Class: org.springframework.boot.loader.PropertiesLauncher

新版MANIFEST.MF文件

Manifest-Version: 1.0
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Start-Class: com.demo.test
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Version: 2.3.12.RELEASE
Main-Class: org.springframework.boot.loader.JarLauncher

可以看到两者主要是main-class不同,只有当

Main-Class: org.springframework.boot.loader.PropertiesLauncher

时,才能加载外部依赖;

在新版本打包时,默认使用了 org.springframework.boot.loader.JarLauncher 在这里插入图片描述

让新版打包时使用

org.springframework.boot.loader.PropertiesLauncher

需要修改打包配置,添加mainfest属性:

manifest { attributes 'Main-Class': 'org.springframework.boot.loader.PropertiesLauncher' }

完整gradle打包配置:

apply plugin: "org.springframework.boot"
apply plugin: "application"

bootJar {
	launchScript()
	mainClassName = 'com.cdv.nsite.central.Central'
	//加載外部依賴包時需要以下配置
	manifest {
		attributes 'Main-Class': 'org.springframework.boot.loader.PropertiesLauncher'
	}
}

springBoot {
	buildInfo()
}

重新打包后,问题解决,可以加载外部依赖;

参考文档:docs.spring.io/spring-boot…