java.lang.IllegalArgumentException: name

3,333 阅读2分钟

一、基本信息

当通过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

二、思路

  1. 抛出异常后看到了sun.misc.URLClassPath$Loader.findResource,第一反应是JDK版本不一致导致的错误。sun包是jvm相关的一个包,不同版本的jdk中sun包可能不一致。但比较后发现JDK版本一致,不是异常的原因。

  2. 查询java.lang.IllegalArgumentException: name后,发现这个异常是springboot加载class错误导致的,参照stackoverflow的帖子解决这个异常。

stackoverflow.com/questions/5…


三、解决流程

  1. 引入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>
  1. 添加包org.springframework.boot.loader

  2. 添加以下类(部分代码)

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代码库中获取。

  1. 编译后,通过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命令行启动是否支持命令行取代?
  • 是否存在更简单或者更新的方法解决这个问题?