it-swarm.com.de

Wie kann ich einen Eigenschaftswert in ein Spring Bean einfügen, das mit Annotationen konfiguriert wurde?

Ich habe einen Haufen Frühlingsbohnen, die über Anmerkungen, z.

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

In der Spring-XML-Datei ist ein PropertyPlaceholderConfigurer definiert:

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

Ich möchte eine der Eigenschaften von app.properites in die oben gezeigte Bean einfügen. Ich kann sowas nicht einfach machen

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

Da PersonDaoImpl nicht in der Spring-XML-Datei enthalten ist (wird über Anmerkungen aus dem Klassenpfad abgerufen). Ich habe so weit wie die folgenden:

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

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

Aber mir ist nicht klar, wie ich auf die Immobilie zugreife, die mich interessiert, von ppc?

281
Dónal

Sie können dies im Frühjahr 3 mithilfe der EL-Unterstützung tun. Beispiel:

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

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

systemProperties ist ein implizites Objekt und strategyBean ist ein Bean-Name.

Ein weiteres Beispiel, das funktioniert, wenn Sie eine Eigenschaft aus einem Properties -Objekt abrufen möchten. Es zeigt auch, dass Sie @Value auf Felder anwenden können:

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

Hier ist ein Blog-Beitrag Ich habe darüber ein bisschen mehr geschrieben.

285
Willie Wheeler

Persönlich liebe ich diesen neuen Weg im Frühjahr 3.0 aus den Dokumenten :

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

Keine Getter oder Setter!

Mit den Eigenschaften, die über die Konfiguration geladen werden:

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

Um meine Freude zu fördern, kann ich sogar das Klicken auf den EL-Ausdruck in IntelliJ steuern und es bringt mich zur Eigenschaftsdefinition!

Es gibt auch die vollständige Nicht-XML-Version :

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

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

Es gibt eine neue Anmerkung @Value in Spring 3.0.0M. @Value unterstützt nicht nur #{...} Ausdrücke, sondern auch ${...} Platzhalter

120
max

<context:property-placeholder ... /> ist das XML-Äquivalent zum PropertyPlaceholderConfigurer.

Beispiel: applicationContext.xml

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

Komponentenklasse

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

Eine andere Alternative besteht darin, die unten gezeigte appProperties-Bean hinzuzufügen:

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

Beim Abrufen kann dieses Bean in einen Java.util.Properties umgewandelt werden, der eine Eigenschaft mit dem Namen results.max enthält, deren Wert aus app.properties gelesen wird. Diese Bean kann wiederum über die Annotation @Resource in eine beliebige Klasse in Abhängigkeit (als Instanz von Java.util.Properties) injiziert werden.

Persönlich bevorzuge ich diese Lösung (gegenüber der von mir vorgeschlagenen), da Sie genau einschränken können, welche Eigenschaften von appProperties verfügbar gemacht werden, und app.properties nicht zweimal lesen müssen.

15
Dónal

Ich benötige zwei Eigenschaftendateien, eine für die Produktion und eine für die Entwicklung (die nicht bereitgestellt werden).

Um beides zu haben, eine Properties Bean, die automatisch verdrahtet werden kann, und einen PropertyConfigurer, können Sie schreiben:

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

und referenzieren Sie das Properties Bean im PropertyConfigurer

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

Bevor wir Spring 3 erhalten, mit dem Sie Eigenschaftskonstanten mithilfe von Annotationen direkt in Ihre Beans einfügen können, habe ich eine Unterklasse der PropertyPlaceholderConfigurer-Bean geschrieben, die das Gleiche tut. So können Sie Ihre Eigenschaftssetzer markieren und Spring wird Ihre Eigenschaften wie folgt automatisch in Ihre Bohnen einspeisen:

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

Die Anmerkung lautet wie folgt:

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

Der PropertyAnnotationAndPlaceholderConfigurer lautet wie folgt:

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);
                    }
                }
            }
        }
    }

}

Fühlen Sie sich frei zu ändern, um zu schmecken

7

Frühling weg:
private @Value("${propertyName}") String propertyField;

ist eine neue Möglichkeit, den Wert mithilfe der Spring-Klasse "PropertyPlaceholderConfigurer" einzufügen. Ein anderer Weg ist anzurufen

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

Hinweis: Für @Value können Sie nicht static propertyField verwenden. Es sollte nur nicht statisch sein, da es sonst null zurückgibt. Um dies zu beheben, wird ein nicht statischer Setter für das statische Feld erstellt und @Value wird über diesem Setter angewendet.

6
hi.nitish

Sie können Ihre Klasse auch mit Anmerkungen versehen:

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

Und haben eine Variable wie diese:

@Autowired
private Environment env;

Jetzt können Sie auf folgende Weise auf alle Ihre Objekte zugreifen:

env.getProperty("database.connection.driver")
6
Alexis Gamarra

Wie bereits erwähnt, erledigt @Value den Job und es ist ziemlich flexibel, da Sie Spring EL darin haben können.

Hier einige Beispiele, die hilfreich sein könnten:

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

Ein anderes, um ein set von einem list zu bekommen

//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;

Sie können auch Werte für Grundtypen festlegen.

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

Sie können statische Methoden aufrufen:

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

Sie können Logik haben

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

Eine mögliche Lösung besteht darin, eine zweite Bean zu deklarieren, die aus derselben Eigenschaftendatei liest:

<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"/>

Die Bean mit dem Namen 'appProperties' ist vom Typ Java.util.Properties und kann mithilfe des oben gezeigten @Resource-Attributs in Abhängigkeit eingefügt werden.

5
Dónal

Wenn Sie mit Spring 2.5 nicht weiterkommen, können Sie für jede Ihrer Eigenschaften eine Bean definieren und sie mithilfe von Qualifikationsmerkmalen injizieren. So was:

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

und

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

Es ist nicht super lesbar, aber es erledigt die Arbeit.

3
Nik

Für mich war es @ Luckys Antwort und speziell die Linie

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

from die Captain Debug Seite

das hat mein Problem behoben. Ich habe eine ApplicationContext-basierte App, die über die Befehlszeile ausgeführt wird und die nach einer Reihe von Kommentaren zu SO von Spring anders als MVC-basierte Apps verkabelt wird.

2
ben3000

Autowiring-Eigenschaftswerte in Spring Beans:

Die meisten Leute wissen, dass Sie @Autowired verwenden können, um Spring anzuweisen, ein Objekt in ein anderes zu injizieren, wenn es Ihren Anwendungskontext lädt. Weniger bekannt ist, dass Sie mit der @ Value-Annotation auch Werte aus einer Eigenschaftendatei in die Attribute einer Bean einfügen können. Weitere Informationen finden Sie in diesem Beitrag.

Neues im Frühjahr 3. || Autowiring-Bean-Werte || Autowiring-Eigenschaftswerte im Frühjahr

2
Lucky

Ich denke, es ist am bequemsten, Eigenschaften in die Bean-Setter-Methode zu injizieren.

Beispiel:

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-Definition:

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

Für jede benannte property Methode setProperty(value) wird aufgerufen.

Diese Methode ist besonders hilfreich, wenn Sie mehr als ein Bean benötigen, das auf einer Implementierung basiert.

Wenn wir zum Beispiel eine weitere Bean in xml definieren:

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

Dann Code wie folgt:

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());

Wird gedruckt

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

In Ihrem Fall sollte es also so aussehen:

@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) {
            ...
        }
    }
}
1
Sergei Pikalev

Wenn Sie mehr Flexibilität für die Konfigurationen benötigen, probieren Sie den Settings4jPlaceholderConfigurer aus: http://settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html

In unserer Anwendung verwenden wir:

  • Einstellungen zur Konfiguration des PreProd- und Prod-Systems
  • Einstellungen und JNDI-Umgebungsvariablen (JNDI überschreibt die Einstellungen) für "mvn jetty: run"
  • Systemeigenschaften für UnitTests (@BeforeClass-Annotation)

Die Standardreihenfolge, in der die Schlüsselwertquelle zuerst überprüft wird, ist beschrieben in:
http://settings4j.sourceforge.net/currentrelease/configDefault.html
Es kann mit einer settings4j.xml (genau auf log4j.xml) in Ihrem Klassenpfad angepasst werden.

Teilen Sie mir Ihre Meinung mit: [email protected]

mit freundlichen Grüßen,
Harald

0
brabenetz