如何将属性值注入到使用注释配置的Spring Bean中?

我有一堆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. properties中的一个属性注入到上面所示的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中访问我感兴趣的属性?

757654 次浏览

一个可能的解决方案是声明第二个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属性注入依赖项。

另一种选择是添加如下所示的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两次。

我需要有两个属性文件,一个用于生产,一个用于开发(将不会部署)。

要同时拥有一个可以自动连接的属性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>

并在propertyconfigururer中引用Properties Bean

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties" ref="appProperties" />
</bean>

您可以在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;

这里是一个博客,我写了关于这一点的更多信息。

在我们得到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);
}
}
}
}
}


}

请随意修改口味

春天3.0.0M3中有一个新的注释@Value@Value不仅支持#{...}表达式,还支持${...}占位符

如果您一直在使用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) {
...

它不是超级可读的,但它完成了工作。

就我个人而言,我喜欢Spring 3.0 来自文档中的这种新方式:

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

没有getter或setter !

通过配置加载属性:

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

<context:property-placeholder ... />是等价于PropertyPlaceholderConfigurer的XML。

< p >的例子: 中< / p >
<context:property-placeholder location="classpath:test.properties"/>

组件类

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

将属性值自动装配到Spring bean中:

大多数人都知道,当Spring加载应用程序上下文时,可以使用@Autowired告诉Spring将一个对象注入另一个对象。一个鲜为人知的信息是,您还可以使用@Value注释将属性文件中的值注入到bean的属性中。

Spring 3.0的新内容 | | 自动装配bean值 | | 在春季自动装配属性值 < / p >

如果你需要更多的灵活性的配置,尝试Settings4jPlaceholderConfigurer: http://settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html < / p >

在我们的应用程序中,我们使用:

  • 配置PreProd-和Prod-System的首选项
  • “mvn jetty:run”的首选项和JNDI环境变量(JNDI覆盖首选项)
  • UnitTests的系统属性(@BeforeClass注释)

首先检查key-value-Source的默认顺序如下:
http://settings4j.sourceforge.net/currentrelease/configDefault.html
它可以在类路径中使用settings4j.xml(精确到log4j.xml)进行定制

让我知道你的意见:settings4j-user@lists.sourceforge.net

致以友好的问候,
哈拉尔德< / p >

对我来说,这是@Lucky的答案,特别是那句台词

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

调试队长页面

这解决了我的问题。我有一个从命令行运行的基于applicationcontext的应用程序,从SO上的许多注释判断,Spring将这些应用程序以不同的方式连接到基于mvc的应用程序。

使用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: / / localhost: 3306 / addvertisement

dev.app.jdbc.username =根

dev.app.jdbc.password =根

你也可以注释你的类:

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

有一个这样的变量:

@Autowired
private Environment env;

现在你可以通过这种方式访问你的所有属性:

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

如前所述,@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;

另一个方法是从list中获得set

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

我认为向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) {
...
}
}
}
< br > < p >春道: <代码>私人@ value (" $ {propertyName} ") 代码字符串propertyField; < / > < / p >

是一种使用Spring的“PropertyPlaceholderConfigurer”类注入值的新方法。 另一种方法是调用

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

注意:对于@Value,你不能使用静态 propertyField,它只能是非静态的,否则返回null。为了解决这个问题,为静态字段创建了一个非静态setter,并在该setter之上应用@Value。

Spring 5中最简单的方法是使用@ConfigurationProperties,这里是一个例子 https://mkyong.com/spring-boot/spring-boot-configurationproperties-example/ < / p >