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

如何在Spring Boot Starter中加载Maven项目属性并添加至Environment?

问题背景

我们有多个Spring Boot应用,配置属性使用@...@占位符引用Maven项目属性,示例如下:

spring.application.name=@project.name@
version=@project.version@
...

这些属性是所有应用共用的,为了避免重复代码,我们想创建一个自定义Spring Boot Starter,把这些属性以最低优先级添加到Environment中。

在自定义Starter里,我们把属性写入custom.properties文件,并创建了CustomEnvironmentPostProcessor来加载这些属性:

public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {

    private final PropertiesPropertySourceLoader loader = new PropertiesPropertySourceLoader();

    @Override
    public void postProcessEnvironment(
            ConfigurableEnvironment environment, SpringApplication application) {
        ClassPathResource path = new ClassPathResource("custom.properties");
        PropertySource<?> propertySource = loadProperties(path);
        environment.getPropertySources().addLast(propertySource);
    }

    private PropertySource<?> loadProperties(ClassPathResource path) {
        Assert.isTrue(path.exists(), () -> "Resource " + path + " does not exist");
        try {
            return this.loader.load("custom-properties", path).get(0);
        } catch (IOException ex) {
            throw new IllegalStateException("Failed to load properties configuration from " + path, ex);
        }
    }
}

但问题是,这些属性并没有被资源过滤覆盖。应用的pom.xml构建配置如下:

<build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

现在想咨询两个问题:

  1. 能否让Starter的属性文件被资源过滤覆盖?
  2. 有没有其他更优的方法,在Spring启动前从pom.xml加载属性并添加至Environment?

解决方案

一、能不能让Starter的属性文件被资源过滤覆盖?

不行。Maven的资源过滤只在构建当前应用项目时生效,只会处理当前项目src/main/resources下的文件,对于依赖的Starter包里的资源文件,Maven不会做二次替换。如果在Starter自己的pom里配置资源过滤,打包时会用Starter自身的Maven属性替换占位符,而不是你期望的应用项目的属性,完全不符合需求,所以这个路子走不通。

二、更优的替代方案

直接读取Maven构建时生成的属性文件,或者通过Maven插件生成自定义属性文件后再加载,比自己维护custom.properties靠谱得多。

方案1:读取Spring Boot默认生成的pom.properties

Spring Boot构建时会自动在target/classes/META-INF/maven/${groupId}/${artifactId}/pom.properties生成文件,里面包含project.name、project.version等核心属性。直接在EnvironmentPostProcessor里读取这个文件即可:

public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {

    private final PropertiesPropertySourceLoader loader = new PropertiesPropertySourceLoader();

    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        Class<?> mainClass = application.getMainApplicationClass();
        // 这里可以根据实际场景调整groupId/artifactId的获取逻辑,比如读取Manifest信息更可靠
        String groupId = mainClass.getPackageName().split("\\.")[0];
        String artifactId = mainClass.getSimpleName();
        
        String mavenPropsPath = String.format("META-INF/maven/%s/%s/pom.properties", groupId, artifactId);
        ClassPathResource resource = new ClassPathResource(mavenPropsPath);
        
        if (resource.exists()) {
            try {
                PropertySource<?> propertySource = loader.load("maven-project-props", resource).get(0);
                environment.getPropertySources().addLast(propertySource); // 设置为最低优先级
            } catch (IOException e) {
                throw new IllegalStateException("Failed to load Maven project properties", e);
            }
        }
    }
}

如果觉得通过包名/类名定位不够稳定,可以遍历classpath:META-INF/maven下的目录,找到对应的pom.properties文件,逻辑稍复杂但容错性更强。

方案2:用Maven插件生成自定义属性文件

在应用的pom.xml里添加properties-maven-plugin,把需要的Maven属性写入指定文件:

<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>properties-maven-plugin</artifactId>
            <version>1.0.0</version>
            <executions>
                <execution>
                    <phase>generate-resources</phase>
                    <goals>
                        <goal>write-project-properties</goal>
                    </goals>
                    <configuration>
                        <outputFile>${project.build.outputDirectory}/shared-project.properties</outputFile>
                        <!-- 可指定只输出需要的属性,避免冗余 -->
                        <properties>
                            <property>project.name</property>
                            <property>project.version</property>
                            <property>project.groupId</property>
                        </properties>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

然后在Starter的EnvironmentPostProcessor里直接读取这个文件,路径明确更可控:

@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
    ClassPathResource resource = new ClassPathResource("shared-project.properties");
    if (resource.exists()) {
        try {
            PropertySource<?> propertySource = loader.load("shared-project-props", resource).get(0);
            environment.getPropertySources().addLast(propertySource);
        } catch (IOException e) {
            throw new IllegalStateException("Failed to load shared project properties", e);
        }
    }
}

这个方案更灵活,能精准控制要暴露给Spring环境的Maven属性。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 16:17:51