资讯动态

Maven资源文件配置:一文讲透resources与testResources标签

发布时间:2026/10/20 12:12:35 来源:尧图企业网站定制
打开任何一个中型项目的pom.xml如果你翻到 这一段大概率会在里面看到 和 这几个标签。很多刚接触Maven的人对着这三个标签一脸懵build好理解就是构建配置resources和testResources到底是干嘛的不写行不行写了之后和默认行为有什么区别这篇教程就把这三个标签一次讲透。我会从Maven的构建生命周期说起讲清楚resources和testResources的默认行为、自定义写法、过滤机制、实战配置最后再分享几个我在真实项目里踩过和排查过的资源文件问题。适合刚学Maven、准备正经管理项目资源文件的人也适合那种“项目跑得好好的但资源总是莫名其妙丢文件”的老兄。1. build、resources、testResources先分清它们在pom.xml里的位次1.1 三个标签的管辖范围先说位次关系这个搞错了后面全是坑。是构建配置的顶层容器所有跟“构建过程”有关的配置都住在它里面比如最终产物名finalName、插件plugins、输出目录directory、以及我们这篇的主角resources和testResources。是 的子元素管的是主代码目录src/main/resources下那些资源文件处理完会进入target/classes最终被装进jar包或者war包。同样也是 的子元素管的是测试代码目录src/test/resources下的资源文件处理完会进入target/test-classes只在测试阶段生效不会进入最终产物。可以这样记resources和testResources是build里的两个“资源处理区”一个负责生产阶段的资源一个负责测试阶段的资源。长得很像但互相独立配置规则也各自分开。1.2 构建生命周期中它们什么时候被触发Maven把一次构建拆成了validate、compile、test、package、install、deploy等多个阶段。资源文件不会自己长腿跑进target目录它靠的是maven-resources-plugin这个插件。这个插件有两个核心目标resources:resources绑定在process-resources阶段处理主资源resources:testResources绑定在process-test-resources阶段处理测试资源注意process-resources阶段在compile之前也就是说资源处理比代码编译更早。这一点很重要比如你用了lombok或者代码里要读取classpath下的配置文件这些文件必须已经在target/classes里编译期的注解处理器和资源加载才能正常工作。所以你在pom里写的 和 本质上是给maven-resources-plugin传递配置参数处理哪些目录、是否过滤、过滤的分隔符是什么、包含哪些文件、排除哪些文件。如果什么都不写插件会用默认规则去捞src/main/resources和src/test/resources。2. resources标签从默认行为到自定义配置的全面拆解2.1 默认资源目录可能不是你想象的那样Maven的默认行为是这样的主资源目录固定为${basedir}/src/main/resources构建时原样复制到target/classes最终打包后位于jar包根路径下测试资源目录固定为${basedir}/src/test/resources构建时复制到target/test-classes如果你用的是标准目录结构pom里什么都不写IDE也能正常识别打包也不会漏文件这就是大多数人最初接触Maven时的状态。但项目一复杂默认行为就不太够用了。举几个常见场景公司统一要求把配置文件放在src/main/conf目录不放在src/main/resources里不同环境部署希望配置文件里的环境占位符在打包时自动替换资源目录里混了个别人误放的大文件希望排除掉不让它进jar包某些资源文件需要指定不同的编码处理避免中文乱码这时候你才需要动resources标签。但这里有一个非常反直觉的规则一旦你在pom里显式写了 默认的src/main/resources不会被额外保留。你会认为是“新增”实际上Maven理解为“全部重定义”。新手看网上的配置照着抄把默认目录丢了还以为是CVS或文件上传出问题了。2.2 自定义资源目录的标准写法直接看一个最常见的写法我把每一行都解释一遍build resources resource directorysrc/main/resources/directory filteringtrue/filtering /resource resource directorysrc/main/conf/directory filteringfalse/filtering /resource /resources /buildresource子标签表示一个资源入口每个入口可以理解成一条“取货传送带”。directory填写资源目录路径写相对路径默认相对项目根目录。filtering表示是否对该目录下的文件做占位符替换默认false。多个resource同时存在时按声明顺序依次处理。如果两个声明处理的是同一目标位置后声明的会覆盖先声明的。所以多个资源目录尽量保证彼此不重叠尤其不要让targetPath指向同一个目录。还有一点directory是可以不存在的。Maven不会因为你写了一个不存在的资源目录就报错它会静默跳过。这个特性容易被误解成“配置没生效”排查半天发现只是目录拼写错误实际处理的是另一个目录。2.3 filtering与delimiter让配置文件活起来filtering是resources标签里最有价值、也最容易出事的功能。它做的事情是处理文件内容时把形如${key}的占位符替换成pom.xml里properties标签定义的值或者外部属性文件里的值。典型场景同一个项目要部署到测试环境和生产环境项目里的application.properties写的是数据库连接、Redis地址、日志路径。如果每个环境都手动改一次文件要么容易漏要么容易把只属于本机的地址推到远程仓库。用filtering可以在打包阶段完成替换。要开启过滤filtering必须显式写成true。替换时默认的分隔符是${...}如果你觉得这个分隔符和别的模板冲突可以自定义plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-resources-plugin/artifactId configuration delimiter/delimiter /configuration /plugin这样占位符就变成了key。有些工程内部规范使用xxx作为占位符就是这个原因。这里要强调一个Feature和Bug之间的微妙区域如果pom的properties里没有定义某个keyfiltering处理时不会直接报错而是可能保留原样的${key}也可能替换成空字符串具体行为取决于插件版本。这就导致运行时配置文件里出现空值异常信息指向数据库地址为空排查时又不好定位。所以凡是开了filtering的资源文件打包后务必检查target/classes里的实际内容别等运行时报错再回头找。2.4 includes和excludes按需筛选资源文件如果资源目录里只想放特定类型的文件用includes和excludes控制。Maven的通配符规则是匹配任意字符但不匹配目录分隔符所以.xml只匹配当前目录下的xml**匹配任意数量的目录层级路径分隔符统一用/不要用反斜杠一个完整示例resource directorysrc/main/resources/directory filteringtrue/filtering includes include**/*.properties/include include**/*.xml/include /includes excludes exclude**/*.sample/exclude /excludes /resource规则优先级上excludes优先于includes。也就是说一个文件即使完全匹配include的规则只要命中exclude最后的结果还是被排除。这个顺序经常有人记反导致某些不该排除的样例配置被过滤掉了。实践建议配置粒度要恰到好处。纯文本、可能带占位符的文件加入过滤范围图片、证书、字体、Excel模板这类二进制文件要么单独放目录并保持filteringfalse要么用excludes直接排除千万别让它们淌filtering这趟浑水。3. testResources测试资源里容易翻车的细节3.1 testResources和resources的真正区别表面上看testResources和resources只是目录不同一个src/test/resources一个src/main/resources。但实际使用中差异很大测试资源里的数据主要有单元测试用的数据初始化脚本、Mock数据、测试证书、各种测试配置properties。它们的共同点是只服务于测试代码不会进入最终交付的jar包。一个关键的知识点是classpath加载顺序。测试执行时target/test-classes会排在target/classes前面。也就是说如果src/test/resources下存在和src/main/resources同名的文件测试读到的是测试资源目录里的那一份。很多“只在测试环境出现的问题”都是因为这个规则——测试数据目录里遗留了一份旧模板覆盖了主资源里正确的新模板。还有一个踩坑点测试资源同样要复制到target/test-classes才生效而这个过程不是直接由主资源的配置来管必须单独配testResources。很多人主资源配了filtering测试资源没配测试时调用配置文件仍然得到原样的占位符卡了半天才意识到两套配置互相独立。3.2 测试资源过滤的典型用法测试资源过滤最常见的用途测试环境要用临时数据库配置但不同机器上的数据库地址不一样。比如src/test/resources/database.properties内容是这样db.url${db.url} db.user${db.user}pom.xml里定义属性properties db.urljdbc:h2:mem:test;DB_CLOSE_DELAY-1/db.url db.usersa/db.user /properties然后配置testResources做过滤testResources testResource directorysrc/test/resources/directory filteringtrue/filtering /testResource /testResources这样跑mvn test时database.properties里的${db.url}会被替换成H2内存数据库的连接串单元测试能正常拿到配置。如果你在CI流水线里通过-D参数覆盖属性比如-Ddb.urljdbc:mysql://ci-host/db测试环境还能无改动切换数据库。3.3 testResources不生效时按这个顺序查如果配置了testResources但测试代码读不到文件我的排查习惯是固定走这几步确认标签位置。 必须是 下面的直接子元素不是 的子元素也不是 的子元素。确认目录真实存在。src/test/resources不存在时Maven不报错安静地跳过处理你盯着pom看半天也看不出端倪。去target/test-classes目录看文件用命令ls -l target/test-classes确认文件是否真的复制进去了以及过滤后的内容是不是你期望的值。如果文件压根没复制问题一定出在pom配置或目录路径上。检查有没有残留的旧构建产物跑mvn clean test排除缓存干扰。检查当前生效的profile。如果你在某个profile里定义属性但执行时没激活这个profile属性就不会被替换。这五步能解决九成以上的testResources不生效问题。其中第三步最实用直接看target目录比一遍遍猜配置有效得多。4. 一份可直接抄作业的资源区配置实例4.1 接近真实项目的示例下面这份配置我经常在偏向Spring Boot的项目里用去掉了一堆花哨插件只保留资源相关的内容build finalNamedemo-app/finalName resources resource directorysrc/main/resources/directory filteringtrue/filtering /resource resource directorysrc/main/scripts/directory filteringfalse/filtering targetPathscript/targetPath /resource /resources testResources testResource directorysrc/test/resources/directory filteringtrue/filtering /testResource /testResources /build逐段说明finalName指定最终构建产物名打出来的jar包是demo-app.jar而不是demo-app-1.0.0.jar团队统一产物名时很有用。第一个resource把默认的src/main/resources重新声明一遍filteringtrue这样application.properties里的环境占位符能在打包时替换。第二个resource引进了src/main/scripts目录里面放服务启动脚本或运维脚本filteringfalse防止脚本内容被错误替换targetPathscript让这类文件单独归类在jar包下的script目录不污染classpath根路径。testResources配置了过滤因为测试资源里有数据库配置这个开关能复用pom属性不用维护两份配置。4.2 targetPath改资源在构建产物中的位置targetPath的作用是重定义资源在输出目录中的位置。比如想让配置文件打包后放到jar包根目录下的config文件夹可以这么写resource directorysrc/main/resources/directory targetPathconfig/targetPath /resource这样target/classes下会生成config目录jar包里也就有了config目录。但这个标签有坑我见过的翻车场景不少改动了classpath根路径如果代码里有ClassPathResource(application.yml)这种写法就找不到了对war包而言targetPath的行为受war插件影响有时候会把资源放到了预期以外的位置经常有人用它来解决“jar包启动后读不到外部配置”的问题但这不是最优解外部化配置更适合用spring.config.location这类参数我的建议是基础项目能不用targetPath就不用它是种“强行改变产物结构”的手段不要滥用。4.3 没有特殊需求时这两个标签可以完全省略你要是问我的项目只用了标准目录不做环境替换不搞自定义资源目录也不排除文件那需要写resources和testResources吗答案是完全不需要。Maven默认行为已经覆盖了最常见的场景。很多人学到一个配置就往上加结果反而把默认的src/main/resources覆盖掉导致配置文件丢失。资源文件配置的原则是“按需显式声明”默认行为够用就别动需要再加。如果你看到网上分享的项目pom里有大段resources配置要先弄清楚他的项目为什么要这么配而不是直接抄。5. 我踩过和排查过的三个资源问题5.1 过滤器把二进制文件改坏了几年前维护一个老项目项目里有几个静态资源文件logo图片、字体文件也放在src/main/resources下。当时为了处理config里的占位符我给resources统一加了filteringtrue。构建的时候日志非常正常没有任何报错但程序起来后图片加载不出来打开target/classes下面的图片文件一看比原始文件大了一圈内容被替换过。原因是二进制文件里存在某种字节序列恰好被Maven的资源过滤识别成了占位符在替换过程中被改写了。Maven并不会对图片、字体和文本文件区别对待它只看文件内容的字节模式一旦起了过滤二进制文件就可能被污染。从此我的配置习惯就是文本类资源和二进制类资源分开目录二进制目录保持filteringfalse或者用includes把参与过滤的文件类型限定为properties、xml、yaml这类纯文本格式。这个教训也直接写进了我给团队定的资源目录规范里。5.2 显式声明resources之后默认目录丢了另一个印象很深的排查案例同事在pom里加了一个额外资源目录但只写了那一个resourceresources resource directorysrc/main/extra/directory /resource /resources结果打出来的jar包里面没了application.yml测试环境启动直接报配置缺失。他第一反应是怀疑打包插件有问题折腾了很久才想到是resources配置把默认行为顶掉了。这个问题讲清楚了其实很简单当你显式声明resources时Maven不再自动处理src/main/resources。你以为是在原有基础上增加其实是把默认配置整体覆盖。所以写了自定义resources一定要把默认目录也补回来除非你真的打算放弃它。为了避免其他人踩同一个坑我会在代码评审里特别留意resources标签见到只写额外目录不写默认目录的直接提醒。5.3 测试资源同名文件覆盖了主资源第三个案例更隐蔽。项目里需求方给了一套Excel模板放在src/main/resources/templates下代码在运行时读取它并生成导出文件。有一次测试人员反馈导出的文件格式不对我本地能复现但运行逻辑看起来没问题最后打开target/test-classes/templates目录发现里面躺着一个旧版本的模板文件。原因就是src/test/resources/templates下也有一份同名文件可能是某个开发阶段为了测试方便放进去的后来一直没删。由于测试类加载classpath时target/test-classes排在target/classes前面测试执行时读到的模板是旧的那份于是行为异常。解决方式很简单测试资源目录里不要放和主资源同名的文件。如果确实需要测试专用的资源副本也要让代码在读取时区分逻辑或者给文件起不同的名字避免shadowing。如果非要在pom层面处理可以在testResources里用excludes把测试资源中和主资源冲突的路径排除掉testResources testResource directorysrc/test/resources/directory filteringtrue/filtering excludes excludetemplates/**/exclude /excludes /testResource /testResources但更干净的做法还是文件命名上就避开不要制造歧义。这三个案例背后其实是同一个原则Maven的资源处理是很底层的复制替换机制它不识别文件含义也不懂“要不要覆盖”一切按你的配置机械执行。所以配置resources时要明确想要什么、不想要什么别留任何模糊地带。花了半天在pom里排错的人大多不是不知道标签怎么拼而是没想清楚默认行为是什么。写配置前先把目录结构理清楚运行时的一半问题都能提前消掉。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑