アノテーションを使用して構成されたSpring Beanにプロパティ値を注入するにはどうすればよいですか?


294

私は注釈を介してクラスパスから取得された一連のSpring Beanを持っています。

@Repository("personDao")
public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao {
    // Implementation omitted
}

Spring XMLファイルでは、PropertyPlaceholderConfigurerが定義されています。

<bean id="propertyConfigurer" 
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="/WEB-INF/app.properties" />
</bean> 

上記のbeanにapp.properitesからプロパティの1つを注入したいと思います。私は単純に次のようなことはできません

<bean class="com.example.PersonDaoImpl">
    <property name="maxResults" value="${results.max}"/>
</bean>

PersonDaoImplはSpring XMLファイルでは機能しないため(注釈を介してクラスパスから取得されます)。私は次のようにしています:

@Repository("personDao")
public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao {

    @Resource(name = "propertyConfigurer")
    protected void setProperties(PropertyPlaceholderConfigurer ppc) {
    // Now how do I access results.max? 
    }
}

しかし、私が興味のあるプロパティにどのようにアクセスするのかは明確ではありませんかppc


1
基本的には同じ質問をしましたが、シナリオは少し異なります:stackoverflow.com/questions/310271/…。これまでのところ、誰もそれに答えることができていません。
スペンサーコルモス2008年

Spring 3.1以降、PropertyPlaceholderConfigurerは推奨クラスではなくなりました。PropertySourcesPlaceholderConfigurer代わりに優先します。いずれの場合も、短いXML定義を使用できます<context:property-placeholder />
Michael Piefel 2013年

回答:


292

ELサポートを使用して、Spring 3でこれを行うことができます。例:

@Value("#{systemProperties.databaseName}")
public void setDatabaseName(String dbName) { ... }

@Value("#{strategyBean.databaseKeyGenerator}")
public void setKeyGenerator(KeyGenerator kg) { ... }

systemPropertiesは暗黙的なオブジェクトでstrategyBeanあり、Bean名です。

Propertiesオブジェクトからプロパティを取得する場合に機能するもう1つの例。また@Value、フィールドに適用できることも示しています。

@Value("#{myProperties['github.oauth.clientId']}")
private String githubOauthClientId;

これについて私がこれについて書いたブログの投稿です。


8
あるsystemPropertiesだけでSystem.getProperties()?私は春の豆の中に自分の性質を注入したい場合、私は定義する必要が推測する<bean id="appProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">ようなものを使用して別のBeanにそれとはその後、読み取った値を@Value("#{appProperties.databaseName}")
ドナル・

11
$ {db.doStuff}の式でプレースホルダーを使用することもできることをmaxの回答から確認してください。そうすれば、PropertiesFactoryBeanは必要なく、placeholderConfigurer
gtrak

9
util:propertiesを使用して独自のプロパティを追加できます。例:<util:properties id = "config" location = "classpath:/spring/environment.properties" />。値を取得する方法については、編集された回答を参照してください。(これはおそらくドンに役立つには遅すぎると思いますが、他の人がうまくいけば恩恵を受けるでしょう。)

2
appname-servlet.xmlファイルでutil:propertiesを使用した場合にのみ機能しました。私のapplicationContext.xml(Spring MVCではない)で定義されたpropertyConfigurerを使用しても機能しませんでした。
Asaf Mesika

:この一部について詳しく説明が、あまりにもこのSOFの質問チェックアウトすることをさらに少し読書については、stackoverflow.com/questions/6425795/...
arcseldon

143

個人的に私はドキュメントから Spring 3.0のこの新しい方法が好きです:

private @Value("${propertyName}") String propertyField;

ゲッターやセッターはありません!

プロパティが設定を介して読み込まれている場合:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
      p:location="classpath:propertyFile.properties" name="propertiesBean"/>

さらに嬉しいことに、IntelliJでEL式のクリックを制御することもでき、プロパティ定義に移動します。

完全に非xmlバージョンもあります:

@PropertySource("classpath:propertyFile.properties")
public class AppConfig {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

9
名前空間にuri xmlns:p = " springframework.org/schema/p "を追加して、p:接頭辞付き属性を使用することを確認してください。
シェーン・リー2012

3
このメソッドがテストコンテキストでは機能するが、メインコンテキストでは機能しないのはなぜですか?
luksmir

9
ため息、アノテーションのみのアプローチを機能させるために何時間も費やし、魔法の静的Bean PropertySauceYadaYadaのこの回答宣言を読んだ後にのみ、何が欠けているかを発見しました。春の愛!
Kranach、2015

@barrymacこんにちは、@ Value(#{...})と@Value($ {...})の違いは何ですか。ありがとう
キム

1
これは私にとってはうまくいきます。ヒントは1つだけです。アノテーション@Componentが必要です。
yaki_nuka

121

新しい注釈がある@Value春3.0.0M3は。式@Valueだけで#{...}なく${...}プレースホルダーもサポート


20
+1例が役立つ場合は、ここにあります-@Value(value = "#{'$ {server.env}'}")または単に@Value( "#{'$ {server.env}'}")
Somu

31

<context:property-placeholder ... /> PropertyPlaceholderConfigurerと同等のXMLです。

例:applicationContext.xml

<context:property-placeholder location="classpath:test.properties"/>  

コンポーネントクラス

 private @Value("${propertyName}") String propertyField;

1
私にとってこれは、自動配線が有効になっている場合にのみ機能しました<context:component-scan base-package="com.company.package" />。参考までにApplicationContext、Webコンテキストではなく、を介してSpringを使用しています。
Mustafa

15

別の方法は、以下に示すappProperties Beanを追加することです。

<bean id="propertyConfigurer"   
  class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="/WEB-INF/app.properties" />
</bean> 


<bean id="appProperties" 
          class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="singleton" value="true"/>

        <property name="properties">
                <props>
                        <prop key="results.max">${results.max}</prop>
                </props>
        </property>
</bean>

取得すると、このBeanは、値が読み取られるjava.util.Propertiesという名前のプロパティを含むにキャストできます。results.maxapp.properties。繰り返しますが、このBeanは、@ Resourceアノテーションを介して(java.util.Propertiesのインスタンスとして)任意のクラスに依存性を注入できます。

個人的には、appPropertiesによって公開されるプロパティを正確に制限でき、app.propertiesを2回読み取る必要がないため、このソリューションを(私が提案した他のソリューションより)好みます。


私もうまくいきます。しかし、@ Valueアノテーションを介してPropertyPlaceholderConfigurerからプロパティにアクセスする他の方法はありません(複数のcongif XMLファイルで複数のPropertyPlaceholderConfigurerを使用する場合)。
Czar

9

2つのプロパティファイルが必要です。1つは本番用で、もう1つは開発用のオーバーライドです(デプロイされません)。

自動配線可能なプロパティBeanとPropertyConfigurerの両方を使用するには、次のように記述します。

<bean id="appProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="singleton" value="true" />

    <property name="ignoreResourceNotFound" value="true" />
    <property name="locations">
        <list>
            <value>classpath:live.properties</value>
            <value>classpath:development.properties</value>
        </list>
    </property>
</bean>

PropertyConfigurerのプロパティBeanを参照する

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="properties" ref="appProperties" />
</bean>

7

Spring 3を取得する前に、アノテーションを使用してプロパティ定数を直接Beanに注入できるようにする前に、同じことを行うPropertyPlaceholderConfigurer Beanのサブクラスを作成しました。したがって、プロパティセッターをマークアップすると、Springは次のようにプロパティをBeanに自動配線します。

@Property(key="property.key", defaultValue="default")
public void setProperty(String property) {
    this.property = property;
}

注釈は次のとおりです。

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Property {
    String key();
    String defaultValue() default "";
}

PropertyAnnotationAndPlaceholderConfigurerは次のとおりです。

public class PropertyAnnotationAndPlaceholderConfigurer extends PropertyPlaceholderConfigurer {

    private static Logger log = Logger.getLogger(PropertyAnnotationAndPlaceholderConfigurer.class);

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties properties) throws BeansException {
        super.processProperties(beanFactory, properties);

        for (String name : beanFactory.getBeanDefinitionNames()) {
            MutablePropertyValues mpv = beanFactory.getBeanDefinition(name).getPropertyValues();
            Class clazz = beanFactory.getType(name);

            if(log.isDebugEnabled()) log.debug("Configuring properties for bean="+name+"["+clazz+"]");

            if(clazz != null) {
                for (PropertyDescriptor property : BeanUtils.getPropertyDescriptors(clazz)) {
                    Method setter = property.getWriteMethod();
                    Method getter = property.getReadMethod();
                    Property annotation = null;
                    if(setter != null && setter.isAnnotationPresent(Property.class)) {
                        annotation = setter.getAnnotation(Property.class);
                    } else if(setter != null && getter != null && getter.isAnnotationPresent(Property.class)) {
                        annotation = getter.getAnnotation(Property.class);
                    }
                    if(annotation != null) {
                        String value = resolvePlaceholder(annotation.key(), properties, SYSTEM_PROPERTIES_MODE_FALLBACK);
                        if(StringUtils.isEmpty(value)) {
                            value = annotation.defaultValue();
                        }
                        if(StringUtils.isEmpty(value)) {
                            throw new BeanConfigurationException("No such property=["+annotation.key()+"] found in properties.");
                        }
                        if(log.isDebugEnabled()) log.debug("setting property=["+clazz.getName()+"."+property.getName()+"] value=["+annotation.key()+"="+value+"]");
                        mpv.addPropertyValue(property.getName(), value);
                    }
                }

                for(Field field : clazz.getDeclaredFields()) {
                    if(log.isDebugEnabled()) log.debug("examining field=["+clazz.getName()+"."+field.getName()+"]");
                    if(field.isAnnotationPresent(Property.class)) {
                        Property annotation = field.getAnnotation(Property.class);
                        PropertyDescriptor property = BeanUtils.getPropertyDescriptor(clazz, field.getName());

                        if(property.getWriteMethod() == null) {
                            throw new BeanConfigurationException("setter for property=["+clazz.getName()+"."+field.getName()+"] not available.");
                        }

                        Object value = resolvePlaceholder(annotation.key(), properties, SYSTEM_PROPERTIES_MODE_FALLBACK);
                        if(value == null) {
                            value = annotation.defaultValue();
                        }
                        if(value == null) {
                            throw new BeanConfigurationException("No such property=["+annotation.key()+"] found in properties.");
                        }
                        if(log.isDebugEnabled()) log.debug("setting property=["+clazz.getName()+"."+field.getName()+"] value=["+annotation.key()+"="+value+"]");
                        mpv.addPropertyValue(property.getName(), value);
                    }
                }
            }
        }
    }

}

好みに合わせて自由に変更してください


3
上記の新しいプロジェクトを作成したことに注意してください: code.google.com/p/spring-property-annotations
Ricardo Gladwell

7

クラスに注釈を付けることもできます。

@PropertySource("classpath:/com/myProject/config/properties/database.properties")

そして、このような変数があります:

@Autowired
private Environment env;

これで、次の方法ですべてのプロパティにアクセスできます。

env.getProperty("database.connection.driver")

7

春の道:
private @Value("${propertyName}") String propertyField;

Springの「PropertyPlaceholderConfigurer」クラスを使用して値を注入する新しい方法です。別の方法は呼び出すことです

java.util.Properties props = System.getProperties().getProperty("propertyName");

注:@Valueの場合、静的 propertyField は使用できません。それは非静的でなければなりません。それ以外の場合はnullを返します。これを修正するには、静的フィールドに非静的セッターを作成し、そのセッターの上に@Valueを適用します。


7

述べたように @Valueした、その仕事をします、そしてあなたがそれに春のELを持つことができるので、それは非常に柔軟です。

ここにいくつかの例があります。

//Build and array from comma separated parameters 
//Like currency.codes.list=10,11,12,13
@Value("#{'${currency.codes.list}'.split(',')}") 
private List<String> currencyTypes;

から取得する別setlist

//If you have a list of some objects like (List<BranchVO>) 
//and the BranchVO has areaCode,cityCode,...
//You can easily make a set or areaCodes as below
@Value("#{BranchList.![areaCode]}") 
private Set<String> areas;

プリミティブ型の値を設定することもできます。

@Value("${amount.limit}")
private int amountLimit;

静的メソッドを呼び出すことができます:

@Value("#{T(foo.bar).isSecurityEnabled()}")
private boolean securityEnabled;

あなたは論理を持つことができます

@Value("#{T(foo.bar).isSecurityEnabled() ? '${security.logo.path}' : '${default.logo.path}'}")
private String logoPath;

5

可能な解決策は、同じプロパティファイルから読み取る2番目のBeanを宣言することです。

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="/WEB-INF/app.properties" />
</bean> 

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

「appProperties」という名前のBeanはjava.util.Propertiesタイプであり、上記の@Resource属性を使用して依存性を注入できます。


4

Spring 2.5を使用している場合は、プロパティごとにBeanを定義し、修飾子を使用してそれらを挿入できます。このような:

  <bean id="someFile" class="java.io.File">
    <constructor-arg value="${someFile}"/>
  </bean>

そして

@Service
public class Thing
      public Thing(@Qualifier("someFile") File someFile) {
...

それは超可読ではありませんが、仕事を成し遂げます。


2

Spring Beanへのプロパティ値の自動配線:

ほとんどの人は、@ Autowiredを使用して、アプリケーションコンテキストをロードするときに、あるオブジェクトを別のオブジェクトに注入するようにSpringに指示できることを知っています。あまり知られていない情報のナゲットは、@ Valueアノテーションを使用して、プロパティファイルからBeanの属性に値を注入することもできることです。詳細については、この投稿を参照してください...

Spring 3.0の新機能 || Bean値の自動配線 || 春の自動配線プロパティ値


2

私にとっては、@ Luckyの答えでした。具体的には、

AutowiredFakaSource fakeDataSource = ctx.getBean(AutowiredFakaSource.class);

キャプテンのデバッグページ

それで問題が解決しました。コマンドラインからApplicationContextベースのアプリを実行していて、SOに関するコメントの数から判断すると、SpringはこれらをMVCベースのアプリとは異なる方法で接続します。


1

プロパティをBeanに注入する最も便利な方法はセッターメソッドだと思います。

例:

package org.some.beans;

public class MyBean {
    Long id;
    String name;

    public void setId(Long id) {
        this.id = id;
    }

    public Long getId() {
        return id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

Bean xml定義:

<bean id="Bean1" class="org.some.beans.MyBean">
    <property name="id" value="1"/>
    <property name="name" value="MyBean"/>
</bean>

すべての名前付きpropertyメソッドsetProperty(value)が呼び出されます。

この方法は、1つの実装に基づいて複数のBeanが必要な場合に特に役立ちます。

たとえば、XMLでもう1つのBeanを定義すると、次のようになります。

<bean id="Bean2" class="org.some.beans.MyBean">
    <property name="id" value="2"/>
    <property name="name" value="EnotherBean"/>
</bean>

次に、次のようにコーディングします。

MyBean b1 = appContext.getBean("Bean1");
System.out.println("Bean id = " + b1.getId() + " name = " + b1.getName());
MyBean b2 = appContext.getBean("Bean2");
System.out.println("Bean id = " + b2.getId() + " name = " + b2.getName());

印刷します

Bean id = 1 name = MyBean
Bean id = 2 name = AnotherBean

したがって、あなたの場合は次のようになります:

@Repository("personDao")
public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao {

    Long maxResults;

    public void setMaxResults(Long maxResults) {
        this.maxResults = maxResults;
    }

    // Now use maxResults value in your code, it will be injected on Bean creation
    public void someMethod(Long results) {
        if (results < maxResults) {
            ...
        }
    }
}

0

構成にさらに柔軟性が必要な場合は、Settings4jPlaceholderConfigurerを試してください。http//settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html

このアプリケーションでは、次のものを使用します。

  • PreProd-およびProd-Systemを構成するための設定
  • 「mvn jetty:run」の設定とJNDI環境変数(JNDIが設定を上書きする)
  • UnitTestsのシステムプロパティ(@BeforeClassアノテーション)

Key-Value-Sourceが最初にチェックされるデフォルトの順序については、http//settings4j.sourceforge.net/currentrelease/configDefault.htmlで説明されています。

これは、クラスパス。

あなたの意見を教えてください:settings4j-user@lists.sourceforge.net

親切に、
ハラルド


-1

Springの「PropertyPlaceholderConfigurer」クラスを使用する

Beanのプロパティとして動的に読み込まれるプロパティファイルを示す簡単な例

<bean id="placeholderConfig"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>/WEB-INF/classes/config_properties/dev/database.properties</value>
        </list>
    </property> 
</bean>

<bean id="devDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="driverClass" value="${dev.app.jdbc.driver}"/>
    <property name="jdbcUrl" value="${dev.app.jdbc.url}"/>
    <property name="user" value="${dev.app.jdbc.username}"/>
    <property name="password" value="${dev.app.jdbc.password}"/>
    <property name="acquireIncrement" value="3"/>
    <property name="minPoolSize" value="5"/>
    <property name="maxPoolSize" value="10"/>
    <property name="maxStatementsPerConnection" value="11000"/>
    <property name="numHelperThreads" value="8"/>
    <property name="idleConnectionTestPeriod" value="300"/>
    <property name="preferredTestQuery" value="SELECT 0"/>
</bean> 

プロパティファイル

dev.app.jdbc.driver = com.mysql.jdbc.Driver

dev.app.jdbc.url = jdbc:mysql:// localhost:3306 / addvertisement

dev.app.jdbc.username = root

dev.app.jdbc.password = root

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.