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
?
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.
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();
}
Es gibt eine neue Anmerkung @Value
in Spring 3.0.0M. @Value
unterstützt nicht nur #{...}
Ausdrücke, sondern auch ${...}
Platzhalter
<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;
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.
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>
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
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.
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")
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;
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.
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.
Für mich war es @ Luckys Antwort und speziell die Linie
AutowiredFakaSource fakeDataSource = ctx.getBean(AutowiredFakaSource.class);
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.
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
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) {
...
}
}
}
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:
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