web-dev-qa-db-ja.com

Springでプロパティプレースホルダーをプログラムで解決する方法

現在、Spring 3.1.0.M1、注釈ベースのWebアプリケーションで作業していますが、アプリケーションの特定の場所でプロパティプレースホルダーを解決するのに問題があります。

ここに物語があります。

1)(DispatcherServletによってロードされた)Webアプリケーションコンテキストでは、

mvc-config.xml:

<!-- Handles HTTP GET requests for /resources/version/**  -->
<resources mapping="/${app.resources.path}/**" location="/static/" cache-period="31556926"/> 

...

<!-- Web properties -->
<context:property-placeholder location="
    classpath:app.properties
    "/>

2)app.propertiesには、特に2つのプロパティがあります。

app.properties:

# Properties provided (filtered) by Maven itself
app.version: 0.1-SNAPSHOT
...

# Static resources mapping
app.resources.path: resources/${app.version}

3)JSP 2.1テンプレートにJSPカスタムタグがあります。このタグは、環境設定、アプリのバージョン、Springテーマの選択などに応じて、完全なリソースパスの構築を担当します。カスタムタグクラスはspring:url実装クラスを拡張するため、通常のurlタグと見なされますが、適切なパスに関する追加の知識があります。

私の問題は、JSPカスタムタグの実装で$ {app.resources.path}を正しく解決できないことです。 JSPカスタムタグは、Springではなくサーブレットコンテナによって管理されるため、DIには参加しません。したがって、通常の@Value( "$ {app.resources.path}")を使用して、Springで自動的に解決することはできません。

そこにあるのはWebアプリケーションコンテキストインスタンスだけなので、プログラムでプロパティを解決する必要があります。

これまで私は試しました:

ResourceTag.Java:

// returns null
PropertyResolver resolver = getRequestContext().getWebApplicationContext().getBean(PropertyResolver.class);
resolver.getProperty("app.resources.path");


// returns null, its the same web context instance (as expected)
PropertyResolver resolver2 = WebApplicationContextUtils.getRequiredWebApplicationContext(pageContext.getServletContext()).getBean(PropertyResolver.class);
resolver2.getProperty("app.resources.path");


// throws NPE, resolver3 is null as StringValueResolver is not bound
StringValueResolver resolver3 = getRequestContext().getWebApplicationContext().getBean(StringValueResolver.class);
resolver3.resolveStringValue("app.resources.path");


// null, since context: property-placeholder does not register itself as PropertySource
Environment env = getRequestContext().getWebApplicationContext().getEnvironment();
env.getProperty("app.resources.path");

だから今私はちょっとそれで立ち往生しています。プレースホルダーを解決する機能はコンテキストのどこかにあることを知っていますが、それを行う正しい方法がわかりません。
確認するヘルプやアイデアは大歓迎です。

36
Max Alexejev

コンテキストプレースホルダーの内部作業に焦点を当てるのではなく、次のように新しいutil:propertiesを簡単に定義できると思います。

<util:properties id="appProperties" location="classpath:app.properties" />

コードでは、次のように使用します。

Properties props = appContext.getBean("appProperties", Properties.class);

または、DIができる場所ならどこでもこのように:

@Value("#{appProperties['app.resources.path']}")
15
Ritesh

Spring 3.0.3以降、EmbeddedValueResolverAwareがあり、appContext.getBeanFactory().resolveEmbeddedValue("${prop}")呼び出しを使用する別の投稿で言及されているのと同じように機能します。

問題を解決するため:

  1. EmbeddedValueResolverAwareインターフェースを実装するクラスを作成すると、リゾルバーが注入されます

  2. 次に、コードスニペットで示されているように、プロパティを取得できる場所:

    String propertyValue = resolver.resolveStringValue("${your.property.name}");
    

そうすると、Beanは必要なプロパティを取得するためにApplicationContextに依存する必要がなくなります。

36
Eds

バージョン3.0以降、SpringはbeanFactoryに文字列リゾルバのリストを保持しています。次のように使用できます。

String value = appContext.getBeanFactory().resolveEmbeddedValue("${prop}");

Javadocは、このメソッドがアノテーション属性などの埋め込み値を解決するためのものであると述べているため、使用方法を回避している可能性がありますが、機能しています。

23
thibr

1つのオプションは、PropertySource(ここではメモリ内の構成を例示するMapPropertySource)をConfigurableEnvironmentに追加し、プロパティを解決するように依頼することです。

public class Foo {

    @Autowired
    private ConfigurableEnvironment env;

    @PostConstruct
    public void setup() {
        env.getPropertySources()
           .addFirst(new MapPropertySource("my-propertysource", 
               ImmutableMap.<String, Object>of("your.property.name", "the value")));
        env.resolvePlaceholders("your.property.name");
    }
}

必要に応じて、Fooクラスに@Configurationアノテーションを付けて、XMLを優先してプログラムによる構成の力を活用します。

5
Johan Sjöberg

もう1つの解決策があります。AspectJでタグクラスを@Configurableにし、コンパイル時またはロード時のウィービングを有効にします。次に、カスタムタグで通常のSpring @Valueアノテーションを使用できます。しかし、実際には、いくつかのクラスのためだけに、織物インフラストラクチャをセットアップしたくありません。 ApplicationContextを介してプレースホルダーを解決する方法を探しています。

1
Max Alexejev