You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot Jar运行时File加载类路径properties报FileNotFoundException

问题解答

路径中的感叹号不是报错的根本原因。
java.io.File 只能访问文件系统中存在的独立文件,无法直接读取Jar压缩包内部的资源条目,这才是问题核心。

  • IDE中运行正常的原因:IDE运行时会把编译后的class、资源文件直接输出到target/classes目录,所有资源都是磁盘上的独立文件,File可以正常寻址访问。
  • Jar运行报错的原因:打包后所有类路径资源都被压缩进Jar这个单一归档文件内,不存在独立的components.properties磁盘文件,自然无法通过File找到对应资源。
    路径中的!是Jar URL协议的标准分隔符,作用是分割Jar包本身的磁盘路径和包内资源的路径,不属于非法字符。你代码中调用resource.getFile()拿到的只是URL的路径片段,不是合法的文件系统路径,用它构造File对象本身就是错误用法,仅在资源是磁盘独立文件时该方式才有效。
    另外你代码中对该配置文件加了变更监听逻辑,Jar包内部的资源是只读的,运行时不会发生变更,该监听逻辑在Jar运行场景下本身就不成立。

修复方案

  • 读取类路径内置资源时,不要通过File访问,直接获取输入流读取即可。将loadConfigurations方法的入参从File改为InputStream,直接调用类加载器的getResourceAsStream()方法获取流,兼容IDE运行、Jar运行等所有场景:
// 替换原有获取File的逻辑
try (InputStream is = this.getClass().getResourceAsStream("/" + ComponentConfigConstants.COMPONENT_CONFIGURATION_FILE)) {
    props.load(is);
}
  • Spring Boot项目优先使用内置的ClassPathResource读取类路径资源,自动适配各种部署场景:
ClassPathResource configResource = new ClassPathResource(ComponentConfigConstants.COMPONENT_CONFIGURATION_FILE);
try (InputStream is = configResource.getInputStream()) {
    props.load(is);
}
  • 如果需要实现配置热更新,不要将配置文件打包在Jar内部,应该放在Jar外部的固定目录(比如Jar同层级的config文件夹),运行时从外部文件路径读取,既可以通过File正常访问,也能实现变更监听。
问题背景
  • 异常场景:Spring Boot项目打包为可执行Jar后运行时触发,IntelliJ IDEA内直接运行无异常
  • 异常类型:java.io.FileNotFoundException
  • 异常时解析到的资源路径:

file:\C:\workspaces\localdb-service\target\localdb-service-0.0.1-SNAPSHOT.jar!\BOOT-INF\classes!\components.properties

  • 核心疑问:路径中的感叹号是否为报错原因,该问题的触发逻辑是什么
相关业务代码
public static void loadConfigurations(File propsFile) throws ComponentConfigIntializationException{
    FileInputStream is = null;
    try {
        if(props ==null){
            props = new Properties(getDefaultConfigurationValues());
        }
        is = new FileInputStream(propsFile);
        props.load(is);
        populateProperties();
        configurationInitialized = true;
    }catch (Exception e) {
        LGR.info("Exception# error occurred in loadConfigurations");
        LGR.info(e);
        throw new ComponentConfigIntializationException(e.getCause());
    }

}

public void init() throws ServletException {
        try{
            LGR.info(LGR.isInfoEnabled() ? "--- ComponentConfigurationLoader.init() , Loading component Configurations" : null);
            URL resource = this.getClass().getResource("/"+ ComponentConfigConstants.COMPONENT_CONFIGURATION_FILE);
            File componentConfigFile = new File(resource.getFile());
            if(componentConfigFile.exists()){
                LGR.info(LGR.isInfoEnabled() ? "--- Component.properties exits" : null);
            }else{
                LGR.info(LGR.isInfoEnabled() ? "--- Component.properties does not exits" + componentConfigFile.getPath(): null);
            }
            ComponentConfigurationProvider.loadConfigurations(componentConfigFile);
            ComponentConfigurationProvider.setRealPath(getServletContext().getRealPath("/"));
            LGR.info(LGR.isInfoEnabled() ? "Configurations Loaded, Starting monitor to observee refresh changings" : null);
            ConfigurationRefresher.startConfigurationMonitoring(componentConfigFile, ComponentConfigurationProvider.getConfigurationRefresherTime());
            initializeSecurityConfigruation(ComponentConfigConstants.SECURITY_FRAME_POLICIES_CONFIGURATION_FILE,true);
            initializeSecurityConfigruation(ComponentConfigConstants.ALLOW_CROSS_DOMAIN_CONFIGURATION_FILE,false);
            initializeBuildConfiguration(ComponentConfigConstants.BUILD_FILE);
        }catch(ComponentConfigIntializationException e){
            LGR.error("#COMPONENT_CONFIG_LOAD_ERROR# Error While Loading Commmon Configurations", e);
        }
        
    }
报错日志
2022-06-21 14:22:43.361  INFO 17392 --- [           main]
c.i.c.f.s.ComponentConfigurationLoader   : ---
ComponentConfigurationLoader.init() , Loading component Configurations
2022-06-21 14:22:43.361  INFO 17392 --- [           main]
c.i.c.f.s.ComponentConfigurationLoader   : --- Component.properties
does not exitsfile:\C:\workspaces\localdb-service\target\localdb-service-0.0.1-SNAPSHOT.jar!\BOOT-INF\classes!\components.properties
2022-06-21 14:22:43.361  INFO 17392 --- [main] c.i.c.f.c.ComponentConfigurationProvider : Exception# error occurred in loadConfigurations
2022-06-21 14:22:43.361  INFO 17392 --- [           main] c.i.c.f.c.ComponentConfigurationProvider :
java.io.FileNotFoundException:
file:\C:\workspaces\localdb-service\target\localdb-service-0.0.1-SNAPSHOT.jar!\BOOT-INF\classes!\components.properties (The filename, directory name, or volume label syntax is incorrect)
2022-06-21 14:22:43.376 ERROR 17392 --- [main] c.i.c.f.s.ComponentConfigurationLoader   :
#COMPONENT_CONFIG_LOAD_ERROR# Error While Loading Commmon Configurations

com.i2c.components.framework.exceptions.ComponentConfigIntializationException: null
at com.i2c.components.framework.config.ComponentConfigurationProvider.loadConfigurations(ComponentConfigurationProvider.java:187) ~[Components3-Core-1.0.jar!/:na]
at com.i2c.components.framework.startup.ComponentConfigurationLoader.init(ComponentConfigurationLoader.java:53) ~[Components3-Core-1.0.jar!/:na]
at javax.servlet.GenericServlet.init(GenericServlet.java:203) [javax.servlet-api-4.0.1.jar!/:4.0.1]

内容的提问来源于stack exchange,提问作者Hammad Ahmad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 15:01:06