Spring Boot从yml文件中读取属性

7
我有一个Spring Boot应用程序,需要从一个yaml文件中读取属性。
代码:
@Component
@PropertySource("classpath:application.yml")
public class ResourceProvider {

    @Autowired
    private Environment env;

    public String getValue(String key) {
        return env.getProperty("app.max.size");
    }
}

YAML文件
app:
  max:
    size: 10

当我尝试这个时,它不起作用。我得到了app.max.size的值为null。对于size,我得到的值是10。
当我使用application.properties时,我能够得到期望的结果。 我做错了什么吗?

application.properties

 app.max.size=10

对于yml文件,它也可以工作。检查一下你的文件。它是yml还是yaml? - GolamMazid Sajib
@PropertySource("classpath:application.yml") 打字错误。 - dassum
@sajib,我已经尝试使用.yml和.yaml两种格式,但仍然得到null的结果。 如果我尝试使用“app”,则会得到空字符串作为结果。 - warrior107
@dassum,哪里错了?如果有错别字,我怎么能得到“size”的值呢? - warrior107
阅读Spring Boot文档。它将自动读取符合正确约定的yaml文件。 - Darren Forsythe
它将是yml文件。yml文件和属性文件是否存在于同一路径中?yml文件在我的项目中运行良好。 - GolamMazid Sajib
4个回答

11

由于您正在使用application.yml文件,因此无需手动将文件加载到上下文中,因为它是spring应用程序的默认配置文件。您可以像下面这样简单地在装饰了@Component的类中使用它们;

@Value("${app.max.size}")
private int size;

如果你想加载自定义的YAML文件,那么在Spring中这将会是一个巨大的问题。使用@PropertySource不能简单地加载YAML文件。虽然这是可行的,但需要一些工作。首先,你需要一个自定义的属性源工厂。在你的情况下,需要一个自定义的YAML属性源工厂。
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Objects;
import java.util.Properties;

public class YamlPropertySourceFactory implements PropertySourceFactory {

    /**
     * Create a {@link PropertySource} that wraps the given resource.
     *
     * @param name     the name of the property source
     * @param resource the resource (potentially encoded) to wrap
     * @return the new {@link PropertySource} (never {@code null})
     * @throws IOException if resource resolution failed
     */
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource)
            throws IOException {
        Properties properties = load(resource);
        return new PropertiesPropertySource(name != null ? name :
                Objects.requireNonNull(resource.getResource().getFilename(), "Some error message"),
                properties);
    }

    /**
     * Load properties from the YAML file.
     *
     * @param resource Instance of {@link EncodedResource}
     * @return instance of properties
     */
    private Properties load(EncodedResource resource) throws FileNotFoundException {
        try {
            YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
            factory.setResources(resource.getResource());
            factory.afterPropertiesSet();

            return factory.getObject();
        } catch (IllegalStateException ex) {
            /*
             * Ignore resource not found.
             */
            Throwable cause = ex.getCause();
            if (cause instanceof FileNotFoundException) throw (FileNotFoundException) cause;
            throw ex;
        }
    }
}

当你使用以下方式时,你需要告诉 @PropertySource 注释要使用这个工厂而不是默认的工厂;

@Component
@PropertySource(value = "classpath:config-prop.yml", factory = YamlPropertySourceFactory.class) // Note the file name with the extension unlike a property file. Also, it's not the `application.yml` file.
public class ResourceProvider { 

    @Value("${app.max.size}")
    private int size;
}

您可以使用上面代码片段中显示的属性的size变量。

但是,如果您正在使用YAML数组声明来获取属性,则即使使用此方式也会有些奇怪。


1
谢谢你的回答。我想我将不得不使用这个。但是我正在寻找一些不必实现“PropertySourceFactory”的东西。 - warrior107
这非常有帮助。非常感谢你。这正是我所需要的。 - Krishna Vedula
不错。有效! - undefined

1

来自文档:

无法使用@PropertySource注释加载YAML文件。因此,如果您需要以这种方式加载值,则需要使用属性文件。

Spring Boot官方文档参考


0
你不能使用@ProperySource注解加载yaml文件。有一件事,我发现你可以使用属性spring.config.location,在这里你可以定义逗号分隔的yaml文件位置。我已经附上了下面的代码片段:
@Data
@Configuration
@RefreshScope
@ConfigurationProperties(prefix = "public.config.app", ignoreUnknownFields = false)
@Slf4j
public class AppServiceConfiguration {

    private Map<String, Object> ios;
    
    private Map<String, Object> android;
    
    private Map<String, Object> buildNumberForIOS;
    
    private Map<String, Object> buildNumberForAndroid;
    
     @PostConstruct
     public void checkIfYamlIsLoaded() {
            log.debug("APP YAML configuration loaded successfully!");
     }
}

这是我在application.properties中定义此属性的方式:
spring.config.location=src/main/resources/app-application.yaml, src/main/resources/web-application.yaml

这是我的示例yaml文件:
public:
  config:
    app:
      ios:
        enableMyContent: true
        warnUserOnMultipleShippingMethods: true
        enableShowScanToOrder: false
      android:
        enableMyContent: true
        warnUserOnMultipleShippingMethods: true
        enableShowScanToOrder: false
      buildNumberForIOS:
        '951': enableCurbsidePickup
      buildNumberForAndroid:
        '585': enableCurbsidePickup
        '595': enableImpulseUpsellOnPDP|enableQuantityLimiter

-2

你可以通过以下方式读取该值:

@Value("${app.max.size}")
private String size;  

public String getValue(String key) {
   return size;
}

我有多个属性,不想为此定义变量。新属性可以添加,不想更改此文件。 - warrior107

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接