ClassLoader.getResource按classpath声明顺序“先到先得”加载首个同名资源;Web容器强制优先加载WEB-INF/classes和WEB-INF/lib;需用getResources获取全部匹配项并手动处理;建议通过前缀隔离、外部化配置、Maven排除等方式避免冲突。

ClassLoader.getResource 处理同名资源时,不会自动去重或合并,而是按类路径(classpath)中 jar/目录的**声明顺序**逐个查找,一旦找到第一个匹配项就立即返回,后续同名资源被忽略。这种“先到先得”机制是资源重名问题的根本原因。
资源加载顺序由 classpath 排序决定
Java 启动时,JVM 按 classpath 参数中路径出现的先后顺序扫描资源。例如:
- 命令行启动:java -cp "lib/a.jar:lib/b.jar:config/" MyApp
- 则 getResource("logback.xml") 会先查 a.jar → 再查 b.jar → 最后查 config/ 目录
- 只要 a.jar 里有 logback.xml,b.jar 和 config/ 中的同名文件就完全不会被加载
Web 容器(如 Tomcat)有特殊优先级规则
在 war 包部署场景下,WebAppClassLoader 会强制将 WEB-INF/classes 和 WEB-INF/lib 下的资源排在最前面:
- war 包内
WEB-INF/classes/application.properties总是优先于所有依赖 jar 中的同名文件 - 即使 spring-boot-autoconfigure-3.3.0.jar 里也有 application.properties,它也永远排在 war 自身资源之后
- 这个行为不依赖 pom.xml 里 dependency 的声明顺序,而是由容器类加载器硬编码决定
用 getResources 替代 getResource 可获取全部同名资源
当需要主动控制多个同名资源(比如合并配置、做版本校验),应改用 ClassLoader.getResources():
- 它返回 Enumeration<URL>,包含 classpath 中所有匹配路径的资源 URL
- 你可以遍历每个 URL,用 openStream() 读取内容,再自行判断用哪个(比如按文件时间戳、版本号字段、或自定义权重)
- 注意:需手动去重(比如检查 URL.toString() 是否已处理过),避免重复加载同一物理文件(如不同 jar 引用了同一个依赖)
避免冲突的实用建议
真正解决问题不靠猜顺序,而靠设计隔离:
- 给配置文件加模块前缀,例如
payment-db.properties、user-cache.properties,而非全项目共用 db.properties - 敏感配置(如数据库密码)绝不打包进 jar,统一放在外部 config 目录,并通过 -Dspring.config.location 指定
- Maven 构建时用
<excludes>显式剔除第三方 jar 中的干扰配置(如排除 spring-batch-core 里的 batch-hsql.properties) - 开发阶段用
ClassLoader.getResources("xxx").asList()打印全部路径,快速确认实际加载来源


















