Java 如何将属性值注入使用注释配置的 Spring Bean?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/317687/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I inject a property value into a Spring Bean which was configured using annotations?
提问by Dónal
I have a bunch of Spring beans which are picked up from the classpath via annotations, e.g.
我有一堆 Spring bean,它们是通过注释从类路径中提取的,例如
@Repository("personDao")
public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao {
// Implementation omitted
}
In the Spring XML file, there's a PropertyPlaceholderConfigurerdefined:
在 Spring XML 文件中,定义了一个PropertyPlaceholderConfigurer:
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/app.properties" />
</bean>
I want to inject one of the properties from app.properites into the bean shown above. I can't simply do something like
我想将 app.properites 中的一个属性注入到上面显示的 bean 中。我不能简单地做类似的事情
<bean class="com.example.PersonDaoImpl">
<property name="maxResults" value="${results.max}"/>
</bean>
Because PersonDaoImpl does not feature in the Spring XML file (it is picked up from the classpath via annotations). I've got as far as the following:
因为 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?
}
}
But it's not clear to me how I access the property I'm interested in from ppc
?
但我不清楚如何访问我感兴趣的财产ppc
?
采纳答案by Willi aus Rohr
You can do this in Spring 3 using EL support. Example:
您可以使用 EL 支持在 Spring 3 中执行此操作。例子:
@Value("#{systemProperties.databaseName}")
public void setDatabaseName(String dbName) { ... }
@Value("#{strategyBean.databaseKeyGenerator}")
public void setKeyGenerator(KeyGenerator kg) { ... }
systemProperties
is an implicit object and strategyBean
is a bean name.
systemProperties
是一个隐式对象,strategyBean
是一个 bean 名称。
One more example, which works when you want to grab a property from a Properties
object. It also shows that you can apply @Value
to fields:
再举一个例子,当你想从一个Properties
对象中获取一个属性时它会起作用。它还表明您可以申请@Value
字段:
@Value("#{myProperties['github.oauth.clientId']}")
private String githubOauthClientId;
Here is a blog postI wrote about this for a little more info.
这是我写的一篇关于此的博客文章,以获取更多信息。
回答by Dónal
A possible solutions is to declare a second bean which reads from the same properties file:
一个可能的解决方案是声明从同一属性文件中读取的第二个 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"/>
The bean named 'appProperties' is of type java.util.Properties and can be dependency injected using the @Resource attruibute shown above.
名为“appProperties”的 bean 是 java.util.Properties 类型,可以使用上面显示的 @Resource 属性进行依赖注入。
回答by Dónal
Another alternative is to add the appProperties bean shown below:
另一种选择是添加如下所示的 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>
When retrieved, this bean can be cast to a java.util.Properties
which will contain a property named results.max
whose value is read from app.properties
. Again, this bean can be dependency injected (as an instance of java.util.Properties) into any class via the @Resource annotation.
检索时,此 bean 可以转换为 a java.util.Properties
,其中将包含一个名为results.max
的属性,其值是从 读取的app.properties
。同样,这个 bean 可以通过 @Resource 注释依赖注入(作为 java.util.Properties 的一个实例)到任何类中。
Personally, I prefer this solution (to the other I proposed), as you can limit exactly which properties are exposed by appProperties, and don't need to read app.properties twice.
就我个人而言,我更喜欢这个解决方案(而不是我提出的另一个),因为您可以精确限制 appProperties 公开哪些属性,并且不需要读取 app.properties 两次。
回答by Willi aus Rohr
I need to have two properties files, one for production and an override for development (that will not be deployed).
我需要有两个属性文件,一个用于生产,一个用于开发(不会部署)。
To have both, a Properties Bean that can be autowired and a PropertyConfigurer, you can write:
要同时拥有可自动装配的 Properties 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>
and reference the Properties Bean in the PropertyConfigurer
并在 PropertyConfigurer 中引用 Properties Bean
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="appProperties" />
</bean>
回答by Ricardo Gladwell
Before we get Spring 3 - which allows you to inject property constants directly into your beans using annotations - I wrote a sub-class of the PropertyPlaceholderConfigurer bean that does the same thing. So, you can mark up your property setters and Spring will autowire your properties into your beans like so:
在我们获得 Spring 3 之前——它允许你使用注解将属性常量直接注入到你的 bean 中——我写了一个 PropertyPlaceholderConfigurer bean 的子类来做同样的事情。因此,您可以标记您的属性设置器,Spring 会将您的属性自动装配到您的 bean 中,如下所示:
@Property(key="property.key", defaultValue="default")
public void setProperty(String property) {
this.property = property;
}
The Annotation is as follows:
注解如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Property {
String key();
String defaultValue() default "";
}
The PropertyAnnotationAndPlaceholderConfigurer is as follows:
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);
}
}
}
}
}
}
Feel free to modify to taste
随意修改口味
回答by Ricardo Gladwell
There is a new annotation @Value
in Spring 3.0.0M3. @Value
support not only #{...}
expressions but ${...}
placeholders as well
有一个新的注释@Value
在春季3.0.0M3。@Value
不仅支持#{...}
表达式,还支持${...}
占位符
回答by Nik
If you are stuck using Spring 2.5 you could define a bean for each of your properties and inject them using qualifiers. Like this:
如果您坚持使用 Spring 2.5,您可以为每个属性定义一个 bean 并使用限定符注入它们。像这样:
<bean id="someFile" class="java.io.File">
<constructor-arg value="${someFile}"/>
</bean>
and
和
@Service
public class Thing
public Thing(@Qualifier("someFile") File someFile) {
...
Its not super readable but it gets the job done.
它不是超级可读,但它完成了工作。
回答by barrymac
Personally I love this new way in Spring 3.0 from the docs:
我个人喜欢文档中 Spring 3.0 中的这种新方式:
private @Value("${propertyName}") String propertyField;
No getters or setters!
没有 getter 或 setter!
With the properties being loaded via the config:
通过配置加载属性:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:propertyFile.properties" name="propertiesBean"/>
To further my glee I can even control click on the EL expression in IntelliJ and it brings me to the property definition!
为了让我更高兴,我什至可以控制单击 IntelliJ 中的 EL 表达式,它将我带到属性定义!
There's also the totally non xml version:
还有完全非 xml 版本:
@PropertySource("classpath:propertyFile.properties")
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
回答by shane lee
<context:property-placeholder ... />
is the XML equivalent to the PropertyPlaceholderConfigurer.
<context:property-placeholder ... />
是等同于 PropertyPlaceholderConfigurer 的 XML。
Example: applicationContext.xml
示例:applicationContext.xml
<context:property-placeholder location="classpath:test.properties"/>
Component class
组件类
private @Value("${propertyName}") String propertyField;
回答by Lucky
Autowiring Property Values into Spring Beans:
将属性值自动装配到 Spring Beans 中:
Most people know that you can use @Autowired to tell Spring to inject one object into another when it loads your application context. A lesser known nugget of information is that you can also use the @Value annotation to inject values from a property file into a bean's attributes. see this post for more info...
大多数人都知道您可以使用 @Autowired 告诉 Spring 在加载应用程序上下文时将一个对象注入另一个对象。一个鲜为人知的信息是,您还可以使用 @Value 注释将属性文件中的值注入到 bean 的属性中。请参阅此帖子以获取更多信息...
new stuff in Spring 3.0||autowiring bean values||autowiring property values in spring