8

我正在将一个工作项目从使用 SpringBoot 命令行参数转移到从文件中读取属性。以下是该@Configuration课程涉及的部分:

@Configuration
class RemoteCommunication {

    @Inject
    StandardServletEnvironment env


    @Bean
    static PropertySourcesPlaceholderConfigurer placeholderConfigurer () {
        // VERIFIED this is executing...
        PropertySourcesPlaceholderConfigurer target = new PropertySourcesPlaceholderConfigurer()
        // VERIFIED this files exists, is readable, is a valid properties file
        target.setLocation (new FileSystemResource ('/Users/me/Desktop/mess.properties'))
        // A Debugger does NOT show this property source in the inject Environment
        target
    }


    @Bean  // There are many of these for different services, only one shown here.
    MedicalSorIdService medicalSorIdService () {
        serviceInstantiator (MedicalSorIdService_EpicSoap, 'uri.sor.id.lookup.internal')
    }


    // HELPER METHODS...


    private <T> T serviceInstantiator (final Class<T> classToInstantiate, final String propertyKeyPrimary) {
        def value = retrieveSpringPropertyFromConfigurationParameter (propertyKeyPrimary)
        classToInstantiate.newInstance (value)
    }


    private def retrieveSpringPropertyFromConfigurationParameter (String propertyKeyPrimary) {
        // PROBLEM: the property is not found in the Environment
        def value = env.getProperty (propertyKeyPrimary, '')
        if (value.isEmpty ()) throw new IllegalStateException ('Missing configuration parameter: ' + "\"$propertyKeyPrimary\"")
        value
    }

使用@Value注入属性确实有效,但是如果可能的话,我宁愿Environment直接使用。如果设置不在,Environment那么我不确定它们是从哪里@Value拉出来的......

env.getProperty()但是,当我传入指定属性的命令行参数时,它仍然可以正常工作。

欢迎任何建议!

4

4 回答 4

19

这里的问题是 和 之间的区别PropertySourcesPlaceholderConfigurerStandardServletEnvironment或者Environment为了简单起见。

Environment是一个支持整体的对象,可以ApplicationContext解析一堆属性(Environment接口扩展PropertyResolver)。AConfigurableEnvironment有一个MutablePropertySources可以通过 检索的对象getPropertySources()。这MutablePropertySources包含一个对象,LinkedList这些PropertySource对象被检查以解析请求的属性。

PropertySourcesPlaceholderConfigurer是具有自己状态的单独对象。它拥有自己的MutablePropertySources对象来解析属性占位符。PropertySourcesPlaceholderConfigurer实现EnvironmentAware所以当ApplicationContext它掌握它时,它给它它的Environment对象。将PropertySourcesPlaceholderConfigurerthis 添加到它自己的EnvironmentMutablePropertySources然后它还会添加Resource您指定的各种对象setLocation()作为附加属性。这些Resource对象不会添加到Environment'sMutablePropertySources中,因此不适用于env.getProperty(String).

所以你不能直接将加载的属性PropertySourcesPlaceholderConfigurer放入Environment。您可以做的是直接添加到Environment'sMutablePropertySouces中。一种方法是使用

@PostConstruct
public void setup() throws IOException {
    Resource resource = new FileSystemResource("spring.properties"); // your file
    Properties result = new Properties();
    PropertiesLoaderUtils.fillProperties(result, resource);
    env.getPropertySources().addLast(new PropertiesPropertySource("custom", result));
}

或者干脆(感谢@M.Deinum)

@PostConstruct
public void setup() throws IOException {
    env.getPropertySources().addLast(new ResourcePropertySource("custom", "file:spring.properties")); // the name 'custom' can come from anywhere
}

请注意,添加 a@PropertySource具有相同的效果,即。直接添加到Environment,但您是静态而不是动态地执行此操作。

于 2014-01-14T04:53:27.590 回答
5

在 SpringBoot 中使用@EnableConfigurationProperties注解就足够了——你不需要 setup PropertySourcesPlaceholderConfigurer

然后在 POJO 上添加注释 @ConfigurationProperties,Spring 会自动注入 application.properties 中定义的属性。

您还可以使用 YAML 文件 - 您只需将适当的依赖项(如 SnakeYaml)添加到类路径

您可以在此处找到详细示例:http: //spring.io/blog/2013/10/30/empowering-your-apps-with-spring-boot-s-property-support

于 2014-01-13T22:14:53.937 回答
3

我在PropertySourcesPlaceholderConfigurer实例化过程中实现了这一点。

@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurerBean(Environment env) {
    PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
    YamlPropertiesFactoryBean yamlFactorybean = new YamlPropertiesFactoryBean();
    yamlFactorybean.setResources(determineResources(env));

    PropertiesPropertySource yampProperties = new PropertiesPropertySource("yml", yamlFactorybean.getObject());

    ((AbstractEnvironment)env).getPropertySources().addLast(yampProperties);

    propertySourcesPlaceholderConfigurer.setProperties(yamlFactorybean.getObject());

    return propertySourcesPlaceholderConfigurer;
}


private static Resource[] determineResources(Environment env){
    int numberOfActiveProfiles = env.getActiveProfiles().length;
    ArrayList<Resource> properties =  new ArrayList(numberOfActiveProfiles);
    properties.add( new ClassPathResource("application.yml") );

    for (String profile : env.getActiveProfiles()){
        String yamlFile = "application-"+profile+".yml";
        ClassPathResource props = new ClassPathResource(yamlFile);

        if (!props.exists()){
            log.info("Configuration file {} for profile {} does not exist");
            continue;
        }

        properties.add(props);
    }

    if (log.isDebugEnabled())
        log.debug("Populating application context with properties files: {}", properties);

    return properties.toArray(new Resource[properties.size()]);
}
于 2018-09-23T19:10:21.717 回答
1

也许您只需要设置-Dspring.config.location=...(或者SPRING_CONFIG_LOCATION作为环境变量)?这具有在运行时向应用程序的默认路径添加一个额外的配置文件的效果,该路径优先于正常application.properties?有关详细信息,请参阅howto 文档

于 2014-01-14T13:26:12.707 回答