2008-11-25 2 views
256

У меня есть куча весенних фасоли, которые собираются из пути к классам через аннотации, например.Как я могу вставить значение свойства в 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> 

Я хочу, чтобы придать одно из свойств из app.properites в фасоли, показанного выше. Я не могу просто сделать что-то вроде

<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

Я задал по существу тот же вопрос, хотя в несколько ином сценарии: http://stackoverflow.com/questions/310271/injecting-beans-into-a-class-outside-the-spring-managed-context , Пока никто не смог ответить на него. – 2008-11-25 17:05:09

+0

Обратите внимание, что с весны 3.1, `PropertyPlaceholderConfigurer` больше не является рекомендуемым классом. Вместо этого вместо этого следует использовать свойство PropertySourcesPlaceholderConfigurer. В любом случае вы можете использовать более короткое определение XML ``. – 2013-10-30 14:09:07

+0

http://stackoverflow.com/questions/28756014/how-to-configure-dynamic-properties-while-using-spring-boot – kervin 2016-07-30 04:35:03

ответ

264

Вы можете сделать это в Весна 3 с поддержкой EL. Пример:

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

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

systemProperties является неявным объектом и strategyBean является именем фасоли.

Еще один пример, который работает, если вы хотите захватить свойство объекта Properties.Он также показывает, что вы можете применить @Value к полям:

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

Вот blog post я писал об этом в немного больше информации.

+7

«SystemProperties» просто `System.getProperties()`? Я предполагаю, что если я хочу вставить свои собственные свойства в компонент Spring, мне нужно определить `` затем прочитать значения из этого в другой компонент, использующий что-то вроде `@Value (" # {appProperties.databaseName} ")` – 2011-04-06 20:50:40

+10

Обязательно обратите внимание на ответ макс, что вы также можете использовать заполнители в выражениях $ {db.doStuff}, тогда вам не понадобится PropertiesFactoryBean, просто placeholderConfigurer – gtrak 2011-07-21 00:15:37

+9

Вы можете добавить свои собственные свойства, используя util: properties; например, . См. Отредактированный ответ о том, как получить значение. (Я понимаю, что, возможно, слишком поздно, чтобы помочь Дэну, но другие, надеюсь, принесут пользу.) – 2012-01-28 19:34:39

5

А возможные решения заключается в объявлении второго компонента, который считывает из одних и тех же свойств файла:

<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» имеет java.util.Properties типа и может быть зависимость впрыскивает с помощью @ Resource attruibute, показанный выше.

14

Другой альтернативой является добавление боб appProperties как показано ниже:

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

Когда получен, этот компонент может быть приведен к java.util.Properties, который будет содержать свойство с именем results.max, значение которого считывается из app.properties. Опять же, этот компонент может быть введен в зависимость (как экземпляр java.util.Properties) в любой класс с помощью аннотации @Resource.

Лично я предпочитаю это решение (другому предложению), так как вы можете ограничить то, какие свойства выставлены appProperties, и не нужно дважды читать app.properties.

+0

Работает и для меня. Но нет другого способа получить доступ к свойствам PropertyPlaceholderConfigurer через аннотацию @Value (при использовании нескольких PropertyPlaceholderConfigurer в нескольких XML-файлах congif)? – Czar 2011-01-27 11:51:23

9

Мне нужно иметь два файла свойств, один для производства и переопределение для разработки (которые не будут развернуты).

Чтобы иметь обоих, свойства Bean, которые могут быть autowired и 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 id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> 
    <property name="properties" ref="appProperties" /> 
</bean> 
6

Прежде чем мы получим Spring 3, который позволяет вам вводить константы свойств непосредственно в ваши бобы с помощью аннотаций - я написал подкласс класса компонента PropertyPlaceholderConfigurer, который делает то же самое. Таким образом, вы можете пометить ваши сеттер собственности и Spring будет autowire своих свойств в ваши бобы так:

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

} 

Не стесняйтесь модифицировать по вкусу

118

T вот новая аннотация @Value в Spring 3.0.0M3. поддержка @Value не только #{...} выражения, но ${...} заполнители, а

3

Если вы застряли с помощью Spring 2.5 вы могли бы определить боб для каждого из ваших свойств и инъекционные их с помощью классификаторов. Как это:

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

и

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

Сво не супер чтения, но он получает работу.

132

Лично я люблю этот новый путь в Spring 3.0 from the docs:

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

Нет добытчиками и сеттеров!

С свойствами загружается через конфиг:

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

Для дальнейшего моего ликования я даже могу контролировать нажмите на выражение EL в IntelliJ и подводит меня к определению собственности!

Там также полностью не XML версия:

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

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

<context:property-placeholder ... /> является XML эквивалентно PropertyPlaceholderConfigurer.

Пример: applicationContext.XML

класс
<context:property-placeholder location="classpath:test.properties"/> 

Компонент

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

Значения автоматического связывания недвижимости в Spring Beans:

Большинство людей знают, что вы можете использовать @Autowired сказать Spring, чтобы ввести один объект в другой, когда его загружает контекст вашего приложения. Менее известным самородком информации является то, что вы также можете использовать аннотацию @Value для вставки значений из файла свойств в атрибуты bean. посмотреть это сообщение для получения дополнительной информации ...

new stuff in Spring 3.0 || autowiring bean values || autowiring property values in spring

0

Если вам нужно больше гибкости для конфигураций, попробуйте Settings4jPlaceholderConfigurer: http://settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html

В нашем приложении мы используем:

  • Параметры для конфигурирования PreProd- и Prod-System
  • Preferences и переменные среды JNDI (JNDI перезаписывает предпочтения) для «mvn jetty: run»
  • Свойства системы для UnitTests (@BeforeClass annotati на)

порядка по умолчанию, какой ключ-значение-Source сначала проверяется, описана в:
http://settings4j.sourceforge.net/currentrelease/configDefault.html
Он может быть настроен с settings4j.xml (с точностью до log4j.xml) в вашем пути к классам.

Позвольте мне знать ваше мнение: [email protected]

с дружеским приветом,
Харальд

2

Для меня это было @ ответ Счастливчика, и, в частности, линия

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

из the Captain Debug page

, что фиксированная моя проблема. У меня есть приложение на основе ApplicationContext, запущенное из командной строки, и, судя по нескольким комментариям к SO, Spring подключается по-разному к приложениям на базе MVC.

-1

Использование Spring в "PropertyPlaceholderConfigurer" класс

Простой пример файла, показывающий свойство чтения динамически как свойство бина

<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.имя пользователя = корень

dev.app.jdbc.password = корень

5

Вы также можете аннотировать вам класс:

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

И имеют переменную так:

@Autowired 
private Environment env; 

Теперь вы могут получить доступ ко всем вашим свойствам таким образом:

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

Как уже упоминалось, @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; 

Другой, чтобы получить set от list

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

Я думаю, что это самый удобный способ, чтобы придать свойства в бобе сеттер метод.

Пример:

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

Бин Определение XML:

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

Для каждого имени property метод setProperty(value) будет вызван.

Этот способ особенно полезен, если вам нужно больше одного компонента на основе одной реализации.

Например, если мы определим еще один компонент в XML:

<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) { 
      ... 
     } 
    } 
} 
6

Spring путь:
private @Value("${propertyName}") String propertyField;

новый способ придать значение, используя класс Spring, "PropertyPlaceholderConfigurer". Другой способ заключается в вызове

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

Примечание: Для @value, вы не можете использовать статический propertyField, он должен быть не статичным только, в противном случае она возвращает нуль. Чтобы исправить это, для статического поля создается нестационарный сеттер, и над этим установщиком применяется @Value.