PropertySourcesPlaceholderConfigurer未在SpringBoot项目中的环境中注册

PropertySourcesPlaceholderConfigurer未在SpringBoot项目中的环境中注册,spring,groovy,spring-boot,Spring,Groovy,Spring Boot,我正在将一个工作项目从使用SpringBoot命令行参数转移到从文件读取属性。以下是@配置类涉及的部分: @Configuration class RemoteCommunication { @Inject StandardServletEnvironment env @Bean static PropertySourcesPlaceholderConfigurer placeholderConfigurer () { // VERIFIED

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

@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
    }
@配置
类远程通信{
@注入
标准服务环境
@豆子
静态属性资源占位符配置器占位符配置器(){
//已验证此正在执行。。。
PropertySourcesPlaceholderConfigurer目标=新的PropertySourcesPlaceholderConfigurer()
//已验证此文件是否存在,是否可读,是否为有效的属性文件
target.setLocation(新文件系统资源('/Users/me/Desktop/mess.properties'))
//调试器在注入环境中不显示此属性源
目标
}
@Bean//对于不同的服务,有很多这样的服务,这里只显示了一个。
医疗服务医疗服务(){
serviceInstantiator(MedicalSorIdService_EpicSoap,'uri.sor.id.lookup.internal')
}
//助手方法。。。
私有T服务实例化器(最终类ClassToInstate,最终字符串propertyKeyPrimary){
def值=检索SpringPropertyFromConfigurationParameter(propertyKeyPrimary)
ClassToInstance.newInstance(值)
}
private def retrieveSpringPropertyFromConfigurationParameter(字符串propertyKeyPrimary){
//问题:在环境中找不到该属性
def值=env.getProperty(propertyKeyPrimary“”)
if(value.isEmpty())抛出新的IllegalStateException('缺少配置参数:'+“\“$propertyKeyPrimary\”)
价值
}
使用
@Value
注入属性确实有效,但是如果可能的话,我宁愿直接使用
环境
。如果设置不在
环境
中,那么我不确定
@Value
从何处提取它们

当我传入指定属性的命令行参数时,
env.getProperty()
仍能正常工作


欢迎任何建议!

在SpringBoot中,使用
@EnableConfigurationProperties
注释就足够了-您不需要设置
属性资源占位符配置器

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

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


您可以在这里找到详细的示例:

这里的问题是
属性资源占位符配置器
标准服务环境
之间的区别,或者为了简单起见
环境

环境
是一个支持整个
应用程序上下文
的对象,可以解析一组属性(
环境
接口扩展了
属性Resolver
).A
ConfigurableEnvironment
有一个
MutablePropertySources
对象,您可以通过
getPropertySources()
检索该对象。此
MutablePropertySources
包含一个
PropertySources
对象的
LinkedList
,这些对象被选中以解析请求的属性

propertysourcesplaceplaceconfigurer
是一个具有自己状态的独立对象。它拥有自己的
MutablePropertySources
对象,用于解析属性占位符。
propertysourcesplaceconfigurer
实现了
EnvironmentAware
,因此当
ApplicationContext
获得它时,它将将其设置为
环境
对象。
属性资源占位符配置器
将此
环境
可变属性资源
添加到自己的
对象中。然后,它还会添加使用
setLocation()指定的各种
资源
对象
作为附加属性。这些
资源
对象未添加到
环境
可变属性资源
,因此不可用于
env.getProperty(String)

因此,您无法将
属性资源占位符配置器
加载的属性直接添加到
环境
。您可以做的是直接添加到
环境
可变属性源
。一种方法是

@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)


请注意,添加一个
@PropertySource
具有相同的效果,即直接添加到
环境中,但您是静态地而不是动态地进行添加。

您可能只需要将
-Dspring.config.location=…
(或者
将SPRING\u config\u location
设置为一个环境变量)?其效果是在运行时向应用程序的默认路径添加一个附加配置文件,该文件优先于正常的
应用程序。属性
?有关详细信息,请参阅。

我在
属性资源占位符配置器
实例化过程中实现了这一点

@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()]);
}
@Bean
公共静态属性资源占位符配置器属性资源占位符配置器bean(环境环境){
PropertySourcesPlaceholderConfigurer PropertySourcesPlaceholderConfigurer=新的PropertySourcesPlaceholderConfigurer();
YamlPropertiesFactoryBean yamlFactorybean=新的YamlPropertiesFactoryBean();
setResources(determineResources(env));
PropertiesPropertySource yampProperties=新的PropertiesPropertySource(“yml”,yamlFactorybean.getObject());
((AbstractEnvironment)env.getPropertySources().addLast(yampProperties);
propertySourcesPlaceholderConfigurer.setProperties(yamlFactorybean.getObject());
返回属性资源占位符配置器;
}
私有静态资源[]确定资源(环境)
@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()]);
}