Как я могу вставить значение свойства в Spring Bean, который был настроен с помощью аннотаций?
У меня есть куча Spring beans, которые извлекаются из пути к классам через аннотации, например.
@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 (его выбирают из класса path через аннотации). У меня есть следующее:
@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
Вы можете сделать это в Spring 3, используя поддержку EL. Пример:
@Value("#{systemProperties.databaseName}")
public void setDatabaseName(String dbName) { ... }
@Value("#{strategyBean.databaseKeyGenerator}")
public void setKeyGenerator(KeyGenerator kg) { ... }
systemProperties
- неявный объект, а strategyBean
- имя bean.
Еще один пример, который работает, когда вы хотите захватить свойство из объекта Properties
. Он также показывает, что вы можете применить @Value
к полям:
@Value("#{myProperties['github.oauth.clientId']}")
private String githubOauthClientId;
Вот сообщение Я написал об этом немного больше информации.
Ответ 2
Лично мне нравится этот новый способ в Spring 3.0 из документов:
private @Value("${propertyName}") String propertyField;
Нет геттеров или сеттеров!
Когда свойства загружаются через config:
<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();
}
Ответ 3
В Spring 3.0.0M3 есть новая аннотация @Value
. @Value
поддерживают не только выражения #{...}
, но и ${...}
заполнители, а
Ответ 4
<context:property-placeholder ... />
является XML-эквивалентом PropertyPlaceholderConfigurer.
Пример:
applicationContext.xml
<context:property-placeholder location="classpath:test.properties"/>
Класс компонентов
private @Value("${propertyName}") String propertyField;
Ответ 5
Другой альтернативой является добавление appProperties bean, показанного ниже:
<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.
Ответ 6
Мне нужно иметь два файла свойств, один для производства и переопределение для разработки (которые не будут развернуты).
Чтобы иметь оба свойства Bean, которые могут быть автообновлены, и 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>
и ссылайтесь на свойства Bean в PropertyConfigurer
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="appProperties" />
</bean>
Ответ 7
Прежде чем мы получим Spring 3 - который позволяет вам вводить константы свойств непосредственно в ваш beans с помощью аннотаций - я написал подкласс класса PropertyPlaceholderConfigurer bean, который делает то же самое. Таким образом, вы можете пометить свои настройки свойств, а Spring будет автоматически расшифровывать ваши свойства в ваш beans так:
@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);
}
}
}
}
}
}
Не стесняйтесь модифицировать по вкусу
Ответ 8
Spring способ:
private @Value("${propertyName}")
String propertyField;
- новый способ ввода значения с помощью класса Spring "PropertyPlaceholderConfigurer".
Другой способ - вызвать
java.util.Properties props = System.getProperties().getProperty("propertyName");
Примечание. Для @Value вы не можете использовать свойство static propertyField, оно должно быть нестатичным, иначе оно возвращает null. Чтобы исправить это, для статического поля создается нестационарный сеттер, и над этим установщиком применяется @Value.
Ответ 9
Возможные решения - объявить второй bean, который читается из одного и того же файла свойств:
<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"/>
bean с именем 'appProperties' имеет тип java.util.Properties и может быть введен в зависимость, используя приведенный выше параметр @Resource.
Ответ 10
Вы также можете аннотировать ваш класс:
@PropertySource("classpath:/com/myProject/config/properties/database.properties")
И у меня есть такая переменная:
@Autowired
private Environment env;
Теперь вы можете получить доступ ко всем своим свойствам следующим образом:
env.getProperty("database.connection.driver")
Ответ 11
Если вы застряли с помощью Spring 2.5, вы можете определить bean для каждого из ваших свойств и ввести их с помощью квалификаторов. Вот так:
<bean id="someFile" class="java.io.File">
<constructor-arg value="${someFile}"/>
</bean>
и
@Service
public class Thing
public Thing(@Qualifier("someFile") File someFile) {
...
Это не очень читаемо, но оно выполняет свою работу.
Ответ 12
Как уже говорилось, @value
выполняйте задание, и оно достаточно гибко, поскольку в нем может быть spring 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;
Ответ 13
Значения свойств Autowiring в Spring Beans:
Большинство людей знают, что вы можете использовать @Autowired, чтобы сообщить Spring вставлять один объект в другой, когда он загружает ваш контекст приложения. Менее известным самородком информации является то, что вы также можете использовать аннотацию @Value для вставки значений из файла свойств в атрибуты bean.
см. этот пост для получения дополнительной информации...
новый материал в Spring 3.0
|| значения autwiring bean
|| значения свойств autowiring в spring
Ответ 14
Для меня это был ответ @Lucky, и, в частности, строка
AutowiredFakaSource fakeDataSource = ctx.getBean(AutowiredFakaSource.class);
from страница Отладка капитана
который исправил мою проблему. У меня есть приложение на основе ApplicationContext, запущенное из командной строки, и, судя по ряду комментариев на SO, Spring прокладывает их по-разному в приложения на основе MVC.
Ответ 15
Если вам нужна дополнительная гибкость для конфигураций, попробуйте параметр Settings4jPlaceholderConfigurer:
http://settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html
В нашем приложении мы используем:
- Настройки для настройки PreProd- и Prod-System
- Предпочтения и переменные среды JNDI (JNDI перезаписывает настройки) для "mvn jetty: run"
- Свойства системы для UnitTests (аннотация @BeforeClass)
Сначала указывается порядок, по которому проверяется ключ-значение-Источник, описан в:
http://settings4j.sourceforge.net/currentrelease/configDefault.html
Его можно настроить с помощью параметра settings4j.xml(с точностью до log4j.xml) в вашем пути к классам.
Сообщите мне свое мнение: [email protected]
с приветливым отношением,
Harald
Ответ 16
Я думаю, что наиболее удобным способом ввода свойств в bean является метод setter.
Пример:
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:
<bean id="Bean1" class="org.some.beans.MyBean">
<property name="id" value="1"/>
<property name="name" value="MyBean"/>
</bean>
При каждом вызове метода property
setProperty(value)
будет вызываться setProperty(value)
.
Этот способ особенно полезен, если вам требуется более одного bean на основе одной реализации.
Например, если мы определяем еще один bean в 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) {
...
}
}
}
Ответ 17
Использовать класс Spring "PropertyPlaceholderConfigurer"
Простой пример, показывающий файл свойств, динамически читаемый как свойство bean
<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://локальный: 3306/addvertisement
dev.app.jdbc.username = корень
dev.app.jdbc.password = корень