Ek açıklamalar kullanılarak yapılandırılmış bir Bahar Fasulyesine bir özellik değerini nasıl enjekte edebilirim?


294

Ek açıklamalarla sınıf yolundan alınan bir demet Bahar fasulyem var, örn.

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

Spring XML dosyasında, tanımlanmış bir PropertyPlaceholderConfigurer vardır :

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

App.properites özelliklerinden birini yukarıda gösterilen fasulye içine enjekte etmek istiyorum. Sadece böyle bir şey yapamam

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

PersondaoImpl, Bahar XML dosyasında bulunmadığından (ek açıklamalarla sınıf yolundan alınır). Aşağıdaki kadarıyla aldım:

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

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

Ama ilgilendiğim mülke nasıl eriştiğimi net değil miyim ppc?


1
Biraz farklı bir senaryoda da olsa, aslında aynı soruyu sordum: stackoverflow.com/questions/310271/… . Şimdiye kadar kimse cevap veremedi.
Spencer Kormos

Bahar 3.1'den itibaren, PropertyPlaceholderConfigurerartık önerilen sınıf olmadığını lütfen unutmayın . PropertySourcesPlaceholderConfigurerBunun yerine tercih edin . Her durumda, daha kısa XML tanımını kullanabilirsiniz <context:property-placeholder />.
Michael Piefel

Yanıtlar:


292

Bunu Bahar 3'te EL desteğini kullanarak yapabilirsiniz. Misal:

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

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

systemPropertiesörtük bir nesnedir ve strategyBeanbir fasulye adıdır.

Nesneden bir özellik almak istediğinizde çalışan bir örnek daha Properties. Ayrıca, @Valuealanlara başvurabileceğinizi gösterir :

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

İşte bu konuda biraz daha fazla bilgi için yazdığım bir blog yazısı .


8
systemPropertiesbasitçe System.getProperties()? Ben bir bahar fasulye içine kendi özellikleri enjekte etmek istiyorum Sanırım ben bir <bean id="appProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">şey kullanarak başka bir fasulye içine o zaman okunan bir değer tanımlamak gerekir@Value("#{appProperties.databaseName}")
Dónal

11
Max'ın cevabından, $ {db.doStuff} ifadelerinde yer tutucuları da kullanabileceğinizi unutmayın, o zaman bir yer
tutucuConfigurer

9
Util: properties; kullanarak kendi özelliklerinizi ekleyebilirsiniz. örneğin, <util: properties id = "config" location = "sınıfyolu: /spring/environment.properties" />. Değeri nasıl alacağınız için düzenlenen cevaba bakınız. (Bunun Don'a yardımcı olmak için muhtemelen çok geç olduğunu anlıyorum, ancak diğerleri umarım fayda sağlayacaktır.)

2
Sadece benim appname-servlet.xml dosyamda util: özellikleri kullandığımda benim için çalıştı. ApplicationContext.xml (Spring MVC değil) içinde tanımlanan propertyConfigurer'ı kullanmak işe yaramadı.
Asaf Mesika

Biraz daha okuma için, bu konu hakkında ayrıntılı bilgi için, bu SOF sorusuna da
göz atın

143

Şahsen ben bu yeni şekilde Bahar 3.0 dokümanlardan seviyorum :

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

Alıcı veya ayarlayıcı yok!

Özellikler config üzerinden yüklenirken:

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

Daha da ilerlemek için IntelliJ'deki EL ifadesine tıklamayı bile kontrol edebilirim ve bu beni mülk tanımına getiriyor!

Tamamen xml olmayan bir sürümü de var :

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

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

9
p: ön ekli özniteliklerini kullanmak için uri xmlns: p = " springframework.org/schema/p " ad alanına emin olun ve ekleyin .
shane lee

3
Bu yöntemler neden test bağlamında çalışır, ancak ana bağlamda çalışmaz?
luksmir

9
iç çekerek, sadece ek açıklamaları işe yarar hale getirmek için saat harcadım ve sadece sihirli bir statik fasulye PropertySauceYadaYada bu bildirimini okuduktan sonra eksik olanı keşfettim. Bahar aşkı!
Kranach

@barrymac hey barry, @Value (# {...}) ve @Value ($ {...}) arasındaki farkın ne olduğunu biliyor musunuz? Teşekkür ederim
Kim

1
Bu benim için çalışıyor. Yalnızca bir ipucu: @Component ek açıklaması gerekir.
yaki_nuka

121

Yeni bir açıklama yoktur @Valueyılında Bahar 3.0.0M3 . @Valueyalnızca #{...}ifadeleri değil, ${...}yer tutucuları da destekleyin


20
+1 Bir örnek yardımcı olursa, işte - @Value (değer = "# {'$ {server.env}'}") veya basitçe @Value ("# {'$ {server.env}'}")
Somu

31

<context:property-placeholder ... /> , PropertyPlaceholderConfigurer öğesine eşdeğer XML'dir.

Örnek: applicationContext.xml

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

Bileşen sınıfı

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

1
Benim için, bu sadece otomatik kablolama ile etkinleştirildiyse çalıştı <context:component-scan base-package="com.company.package" />Referans için ApplicationContext, web bağlamında değil, yay üzerinden kullanıyorum .
Mustafa

15

Başka bir alternatif, aşağıda gösterilen appProperties fasulyesini eklemektir:

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

Alındığında, bu fasulye değeri okunan java.util.Propertiesbir özellik içeren bir çekirdeğe dökülebilir . Yine, bu fasulye @Jource.util.Properties örneği olarak @Resource notu ile herhangi bir sınıfa bağımlılık enjekte edilebilir.results.maxapp.properties

Kişisel olarak, bu özellikleri (önerdiğim diğer çözümlere) tercih ediyorum, çünkü tam olarak hangi özelliklerin appProperties tarafından maruz kaldığını sınırlayabiliyorsunuz ve app.properties'i iki kez okumak zorunda değilsiniz.


Benim için de çalışıyor. Ancak @Value ek açıklaması yoluyla bir PropertyPlaceholderConfigurer'dan özelliklere erişmenin başka bir yolu yoktur (birkaç congif XML dosyasında birden fazla PropertyPlaceholderConfigurer kullanılırken)?
Çar

9

Biri üretim ve geliştirme için bir geçersiz kılma olmak üzere iki özellik dosyaları olması gerekir (dağıtılmaz).

Her ikisine de sahip olmak için, otomatik olarak bağlanabilen bir Özellikler Bean'e ve bir PropertyConfigurer'a aşağıdakileri yazabilirsiniz:

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

ve PropertyConfigurer'daki Properties Bean'e bakın ve

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

7

Ek açıklamaları kullanarak özellik sabitlerini doğrudan fasulyenize enjekte etmenizi sağlayan Bahar 3'ü almadan önce, aynı şeyi yapan PropertyPlaceholderConfigurer fasulyesinin bir alt sınıfını yazdım. Böylece, mülk ayarlayıcılarınızı işaretleyebilirsiniz ve Spring, mülklerinizi fasulye gibi otomatik olarak bağlar:

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

Ek Açıklama aşağıdaki gibidir:

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

PropertyAnnotationAndPlaceholderConfigurer aşağıdaki gibidir:

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

}

Zevkinize göre değişiklik yapmaktan çekinmeyin


3
Yukarıdakiler için yeni bir proje oluşturduğumu lütfen unutmayın: code.google.com/p/spring-property-annotations
Ricardo Gladwell

7

Ayrıca sınıfınıza not ekleyebilirsiniz:

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

Ve şöyle bir değişken var:

@Autowired
private Environment env;

Artık tüm mülklerinize şu şekilde erişebilirsiniz:

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

7

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

Spring'in "PropertyPlaceholderConfigurer" sınıfını kullanarak değeri enjekte etmenin yeni bir yoludur. Başka bir yol da aramak

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

Not: @Value için statik propertyField öğesini kullanamazsınız , yalnızca statik olmamalıdır, aksi halde null değerini döndürür. Bunu düzeltmek için statik alan için statik olmayan bir ayarlayıcı oluşturulur ve bu ayarlayıcının üstüne @Değer uygulanır.


7

Belirtildiği gibi @Valueiş yapar ve içinde bahar EL olabilir gibi oldukça esnektir.

İşte size yardımcı olabilecek bazı örnekler:

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

Başka setbirlist

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

İlkel türler için de değerler ayarlayabilirsiniz.

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

Statik yöntemleri çağırabilirsiniz:

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

Mantığa sahip olabilirsin

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

5

Olası bir çözüm, aynı özellikler dosyasından okunan ikinci bir fasulye beyan etmektir:

<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' adlı fasulye java.util.Properties türündedir ve yukarıda gösterilen @Kaynak özniteliği kullanılarak bağımlılık enjekte edilebilir.


4

İlkbahar 2.5 ile sıkışıp kalırsanız, özelliklerinizin her biri için bir fasulye tanımlayabilir ve niteleyiciler kullanarak enjekte edebilirsiniz. Bunun gibi:

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

ve

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

Süper okunabilir değil ama işi hallediyor.


2

Otomatik Fasulye Özellik Değerlerini Bahar Fasulyesine Bağlama:

Çoğu kişi @Autowired kullanarak Spring'e uygulama içeriğinizi yüklediğinde bir nesneyi diğerine enjekte etmesini söyleyebileceğinizi bilir. Daha az bilinen bir bilgi külçesi, @Value ek açıklamasını, bir özellik dosyasından bir çekirdeğin özniteliklerine değer enjekte etmek için de kullanabilmenizdir. daha fazla bilgi için bu gönderiye bakın ...

3.0'da yeni şeyler || otomatik kablolama fasulye değerleri || ilkbaharda otomatik kablolama özellik değerleri


2

Benim için bu, Lucky'nin cevabı ve özellikle de

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

dan Kaptan ayıklama sayfa

bu benim sorunumu çözdü. Komut satırından çalışan ve SO yorumların bir dizi değerlendirerek ApplicationContext tabanlı bir uygulama var, Bahar MVC tabanlı uygulamalar için bu farklı kablolar.


1

Ben fasulye özellikleri enjekte etmenin en uygun yolu setter yöntemi olduğunu düşünüyorum.

Misal:

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

Fasulye xml tanımı:

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

Her adlandırılmış propertyyöntem setProperty(value)için çağrılacaktır.

Bu şekilde, bir uygulamaya dayalı olarak birden fazla fasülyeye ihtiyacınız varsa özellikle yararlıdır.

Örneğin, xml'de bir tane daha fasulye tanımlarsak:

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

Sonra şöyle kodlayın:

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

Yazdırılacak

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

Yani, sizin durumunuzda şöyle görünmelidir:

@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

Yapılandırmalar için daha fazla Esnekliğe ihtiyacınız varsa, Settings4jPlaceholderConfigurer'ı deneyin: http://settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html

Bizim uygulamada kullanıyoruz:

  • PreProd ve Prod Sistemini yapılandırma tercihleri
  • "Mvn jetty: run" için Tercihler ve JNDI Ortam değişkenleri (JNDI tercihlerin üzerine yazar)
  • UnitTests için Sistem Özellikleri (@BeforeClass ek açıklaması)

İlk olarak anahtar / değer-Kaynağının kontrol edildiği varsayılan sipariş şu adreste açıklanmıştır:
http://settings4j.sourceforge.net/currentrelease/configDefault.html
Bu, sınıf yolu.

Fikrinizi bildirin: settings4j-user@lists.sourceforge.net

Saygılarımla,
Harald


-1

Spring'in "PropertyPlaceholderConfigurer" sınıfını kullanın

Özellik dosyasını, fasulye özelliği olarak dinamik olarak okunan basit bir örnek

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

Özellik Dosyası

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

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

dev.app.jdbc.username = kök

dev.app.jdbc.password = kök

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.