Как я могу ввести значение свойства в Spring Bean, который был настроен с помощью аннотаций? - PullRequest
280 голосов
/ 25 ноября 2008

У меня есть куча бобов Spring, которые извлекаются из classpath с помощью аннотаций, например,

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

В XML-файле Spring определено PropertyPlaceholderConfigurer :

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

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

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

Поскольку PersonDaoImpl не представлен в XML-файле Spring (он выбирается из пути к классам с помощью аннотаций). Я получил следующее:

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

Ответы [ 17 ]

282 голосов
/ 04 декабря 2008

Вы можете сделать это в Spring 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;

Вот пост в блоге Я написал об этом для получения дополнительной информации.

140 голосов
/ 06 октября 2011

Лично я люблю этот новый способ весной 3.0 из документов :

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();
    }
119 голосов
/ 28 июля 2009

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

30 голосов
/ 31 октября 2012

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

Пример: applicationContext.xml

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

Класс компонентов

 private @Value("${propertyName}") String propertyField;
14 голосов
/ 25 ноября 2008

Другая альтернатива - добавить компонент 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>

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

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

9 голосов
/ 26 ноября 2008

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

Чтобы иметь оба, Бин свойств, который может быть подключен автоматически, и 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 голосов
/ 23 февраля 2009

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

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

}

Не стесняйтесь изменять по вкусу

6 голосов
/ 25 октября 2016

Весенний путь:
private @Value("${propertyName}") String propertyField;

- это новый способ ввода значения с помощью класса Spring «PropertyPlaceholderConfigurer». Другой способ - позвонить

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

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

6 голосов
/ 09 января 2015

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

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

И есть такая переменная:

@Autowired
private Environment env;

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

env.getProperty("database.connection.driver")
5 голосов
/ 25 ноября 2008

Возможное решение - объявить второй компонент, который читает из того же файла свойств:

<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, показанного выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...