一、基本信息
当通过jar包启动时,抛出了异常java.lang.IllegalArgumentException: name,具体的异常信息如下:
java.lang.IllegalArgumentException: name
at sun.misc.URLClassPath$Loader.findResource(Unknown Source) ~[na:1.8.0_171]
at sun.misc.URLClassPath.findResource(Unknown Source) ~[na:1.8.0_171]
at java.net.URLClassLoader$2.run(Unknown Source) ~[na:1.8.0_171]
at java.net.URLClassLoader$2.run(Unknown Source) ~[na:1.8.0_171]
at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_171]
at java.net.URLClassLoader.findResource(Unknown Source) ~[na:1.8.0_171]
at org.springframework.boot.loader.LaunchedURLClassLoader.findResource(LaunchedURLClassLoader.java:58) ~[extension-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at java.lang.ClassLoader.getResource(Unknown Source) ~[na:1.8.0_171]
at java.net.URLClassLoader.getResourceAsStream(Unknown Source) ~[na:1.8.0_171]
jar包运行环境及对应依赖:
- window server 2016
- java version "1.8.0_291"
- springboot 2.5.0
二、思路
-
抛出异常后看到了
sun.misc.URLClassPath$Loader.findResource,第一反应是JDK版本不一致导致的错误。sun包是jvm相关的一个包,不同版本的jdk中sun包可能不一致。但比较后发现JDK版本一致,不是异常的原因。 -
查询
java.lang.IllegalArgumentException: name后,发现这个异常是springboot加载class错误导致的,参照stackoverflow的帖子解决这个异常。
三、解决流程
- 引入springboot加载包的maven
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-loader -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader</artifactId>
<version>2.5.6</version>
</dependency>
-
添加包
org.springframework.boot.loader -
添加以下类(部分代码)
package org.springframework.boot.loader;
public class LaunchedURLClassLoader extends URLClassLoader {
...
@Override
public URL findResource(String name) {
// This is where I added the dirty hack
if (name.contains(":\") && !name.startsWith("file:///")) {
System.out.println("URL findResource(name): " + name); // just for you to debug
name = "file:///" + name.replace("\", "/");
System.out.println("URL findResource(name): Reaplced to " + name); // just for you to debug
}
Handler.setUseFastConnectionExceptions(true);
try {
return super.findResource(name);
}
finally {
Handler.setUseFastConnectionExceptions(false);
}
}
...
}
如上,替换findResource即可。其余的代码,可以在Springboot代码库中获取。
- 编译后,通过
java -jar xx.jar发现依旧存在该异常,打开jar包发现该类并没有被编译到需要的位置。这个类是maven插件生成的,路径为org.springframework.boot.loader,而我编译的类位于BOOT-INF/classes/org.springframework.boot.loader,替换后生效。
四、通过修改插件依赖包
使用的打包插件是spring-boot-maven-plugin,该插件的spring-boot-loader-tools包中有需要修改的类。替换后通过以下脚本安装到本地库:
mvn install:install-file -DgroupId=org.springframework.boot -DartifactId=spring-boot-loader-tools -Dversion=local -Dpackaging=jar -Dfile=spring-boot-loader-tools.jar
maven相关配置如下:
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.simtek.cosimcloud.web.CosimcloudWebApplication</mainClass>
<excludeDevtools>true</excludeDevtools>
<includeSystemScope>true</includeSystemScope>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader-tools</artifactId>
</exclude>
</excludes>
</configuration>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-loader-tools</artifactId>
<version>local</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
excludes标签用于排除jar包。
五、待续
- 是否通过特定的框架在编译时修改对应类?
- java命令行启动是否支持命令行取代?
- 是否存在更简单或者更新的方法解决这个问题?