web-dev-qa-db-ja.com

PropertyPlaceholderConfigurer Beanを含むSpring @Configurationファイルは@Valueアノテーションを解決しません

次の構成ファイルがあります。

@Configuration
public class PropertyPlaceholderConfigurerConfig {

    @Value("${property:defaultValue}")
    private String property;

    @Bean
    public static PropertyPlaceholderConfigurer ppc() throws IOException {
        PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
        ppc.setLocations(new ClassPathResource("properties/" + property + ".properties"));
        ppc.setIgnoreUnresolvablePlaceholders(true);
        return ppc;
    }
}

次のVMオプションでアプリケーションを実行します:

-Dproperty=propertyValue

そのため、起動時に特定のプロパティファイルをアプリケーションに読み込むようにします。しかし、この段階で何らかの理由で@Value注釈は処理されず、プロパティはnullです。一方、XMLファイルでPropertyPlaceholderConfigurerを構成している場合は、すべてが期待どおりに機能します。 XMLファイルの例:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="ignoreResourceNotFound" value="true"/>
    <property name="location">
        <value>classpath:properties/${property:defaultValue}.properties</value>
    </property>
</bean>

別のSpring構成ファイルにプロパティ値を注入しようとすると、適切に注入されます。 PropertyPlaceholderConfigurer Beanの作成をその構成ファイルに移動すると、フィールド値は再びnullになります。

回避策として、次のコード行を使用します。

System.getProperties().getProperty("property", "defaultValue")

どちらも機能しますが、なぜこのような動作が発生するのかを知りたいのですが、XMLを使用せずに他の方法で書き換えることができますか?

19
Oleksii Duzhyi

Springから JavaDoc

PropertySourceのプロパティを使用して、定義または@Valueアノテーションの$ {...}プレースホルダーを解決するには、PropertySourcesPlaceholderConfigurerを登録する必要があります。これはXMLで使用すると自動的に発生しますが、@ Configurationクラスを使用する場合は静的な@Beanメソッドを使用して明示的に登録する必要があります。詳細と例については、@ Configurationのjavadocの「外部化された値の操作」セクションおよび@Beanのjavadocの「BeanFactoryPostProcessorが返す@Beanメソッドに関する注意」を参照してください。

そのため、プレースホルダー処理を有効にするために必要なコードブロックでプレースホルダーを使用しようとしています。

@ M.Deinumが述べたように、PropertySource(デフォルトまたはカスタム実装)を使用する必要があります。

以下の例は、PropertySourceアノテーションでプロパティを使用する方法と、フィールドのPropertySourceからプロパティを注入する方法を示しています。

@Configuration
@PropertySource(
          value={"classpath:properties/${property:defaultValue}.properties"},
          ignoreResourceNotFound = true)
public class ConfigExample {

    @Value("${propertyNameFromFile:defaultValue}")
    String propertyToBeInjected;

    /**
     * Property placeholder configurer needed to process @Value annotations
     */
     @Bean
     public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
     }
}
38
proactive-e

他のクラスで動作するときに、これをいくつかのConfigurationクラスで動作させることができなかった他の貧しい人々のために:

そのクラスにある他のBeanを確認し、それらのBeanのいずれかがApplicationContextの初期にインスタンス化されるかどうかを確認します。 ConversionServiceはその一例です。これにより、必要なものが登録される前にConfigurationクラスがインスタンス化され、プロパティの挿入が行われなくなります。

ConversionServiceをインポートした別の構成クラスに移動することで、これを修正しました。

6
George Hilios

VMオプションを使用してアプリケーションを実行し、アプリケーションでそのオプションにアクセスする場合は、わずかに異なる操作を行う必要があります。

@Value("#{systemProperties.property}")
private String property;

PropertyPlaceholderConfigurerはシステムプロパティを認識しません。また、$-プレースホルダーと#はBeanを指します。systemPropertiesはBeanです。

2