我有一堆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中。我不能简单地做一些像
这样的事情<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
访问我感兴趣的属性?
答案 0 :(得分:280)
您可以使用EL支持在Spring 3中执行此操作。例如:
@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;
这是blog post我写的关于这个的更多信息。
答案 1 :(得分:139)
我个人喜欢Spring 3.0 from the docs中的这种新方式:
private @Value("${propertyName}") String propertyField;
没有吸气剂或安装者!
通过config:
加载属性<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:propertyFile.properties" name="propertiesBean"/>
为了让我高兴,我甚至可以控制点击IntelliJ中的EL表达式,它会带我进入属性定义!
还有完全非xml版本:
@PropertySource("classpath:propertyFile.properties")
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
答案 2 :(得分:119)
Spring 3.0.0M3 中有一个新的注释@Value
。 @Value
不仅支持#{...}
个表达式,还支持${...}
个占位符
答案 3 :(得分:30)
<context:property-placeholder ... />
是与PropertyPlaceholderConfigurer等效的XML。
实施例: 的applicationContext.xml
<context:property-placeholder location="classpath:test.properties"/>
组件类
private @Value("${propertyName}") String propertyField;
答案 4 :(得分:14)
另一种方法是添加如下所示的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可以通过@Resource注释依赖注入(作为java.util.Properties的一个实例)到任何类中。
就个人而言,我更喜欢这个解决方案(我建议的另一个),因为你可以准确地限制appProperties公开的属性,而不需要两次读取app.properties。
答案 5 :(得分:9)
我需要有两个属性文件,一个用于生产,一个用于开发的覆盖(不会被部署)。
要同时拥有可以自动装配的属性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>
并引用PropertyConfigurer
中的Properties Bean<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="appProperties" />
</bean>
答案 6 :(得分:6)
在我们获得Spring 3之前 - 它允许您使用注释将属性常量直接注入到bean中 - 我编写了一个PropertyPlaceholderConfigurer bean的子类,它执行相同的操作。因此,您可以标记您的属性设置器,Spring会将您的属性自动装入您的bean中,如下所示:
@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);
}
}
}
}
}
}
随意修改味道
答案 7 :(得分:6)
春天的方式:
private @Value("${propertyName}")
String propertyField;
是使用Spring的“PropertyPlaceholderConfigurer”类注入值的新方法。 另一种方法是打电话
java.util.Properties props = System.getProperties().getProperty("propertyName");
注意:对于@Value,您不能使用 static propertyField,它应该只是非静态的,否则返回null。要修复它,会为静态字段创建一个非静态setter,并在该setter上方应用@Value。
答案 8 :(得分:6)
您也可以为您注释课程:
@PropertySource("classpath:/com/myProject/config/properties/database.properties")
并有一个这样的变量:
@Autowired
private Environment env;
现在您可以通过以下方式访问所有属性:
env.getProperty("database.connection.driver")
答案 9 :(得分:5)
可能的解决方案是声明从同一属性文件中读取的第二个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"/>
名为'appProperties'的bean的类型为java.util.Properties,可以使用上面显示的@Resource attruibute进行依赖注入。
答案 10 :(得分:5)
如上所述,@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;
答案 11 :(得分:3)
如果您使用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 :(得分:2)
将属性值自动装配到Spring Bean中
大多数人都知道你可以使用@Autowired告诉Spring在加载应用程序上下文时将一个对象注入另一个对象。一个鲜为人知的信息块是,您还可以使用@Value注释将属性文件中的值注入到bean的属性中。 有关详细信息,请参阅此帖...
new stuff in Spring 3.0 || autowiring bean values || autowiring property values in spring
答案 13 :(得分:2)
对我来说,这是@Lucky的回答,具体来说就是
AutowiredFakaSource fakeDataSource = ctx.getBean(AutowiredFakaSource.class);
解决了我的问题。我有一个基于ApplicationContext的应用程序从命令行运行,并通过一些关于SO的评论判断,Spring将这些与基于MVC的应用程序联系起来。
答案 14 :(得分:1)
我认为将属性注入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)
都将被调用。
如果您需要基于一个实现的多个bean,这种方式特别有用。
例如,如果我们在xml中再定义一个bean:
<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) {
...
}
}
}
答案 15 :(得分:0)
如果您需要更多灵活性配置,请尝试Settings4jPlaceholderConfigurer: http://settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html
在我们的应用程序中,我们使用:
首先检查key-value-Source的默认顺序,如下所述:
http://settings4j.sourceforge.net/currentrelease/configDefault.html
它可以使用类路径中的settings4j.xml(精确到log4j.xml)进行自定义。
让我知道您的意见:settings4j-user@lists.sourceforge.net
友好的问候,
哈拉尔德
答案 16 :(得分:-1)
使用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 =根
答案 17 :(得分:-1)
Spring 5中最简单的方法是使用@ConfigurationProperties
,这里是示例
https://mkyong.com/spring-boot/spring-boot-configurationproperties-example/