304

我有一堆 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

4

18 回答 18

299

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

这是我写的一篇博文,以获取更多信息。

于 2008-12-04T07:41:12.197 回答
149

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

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

没有吸气剂或二传手!

通过配置加载属性:

<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();
    }
于 2011-10-06T14:02:59.783 回答
123

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

于 2009-07-28T09:05:41.717 回答
31

<context:property-placeholder ... />是与 PropertyPlaceholderConfigurer 等效的 XML。

示例:applicationContext.xml

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

组件类

 private @Value("${propertyName}") String propertyField;
于 2012-10-31T15:19:05.967 回答
15

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

于 2008-11-25T17:25:27.383 回答
10

如前所述@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;
于 2016-05-21T03:58:00.743 回答
9

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

要同时拥有一个可以自动装配的 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>

并在 PropertyConfigurer 中引用 Properties Bean

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="properties" ref="appProperties" />
</bean>
于 2008-11-26T07:19:32.833 回答
8

你也可以注释你的类:

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

并有一个像这样的变量:

@Autowired
private Environment env;

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

env.getProperty("database.connection.driver")
于 2015-01-09T20:01:27.893 回答
7

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

}

随意修改口味

于 2009-02-23T11:08:44.650 回答
7

弹簧方式:
private @Value("${propertyName}") String propertyField;

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

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

注意:@Value 不能使用静态属性字段,只能是非静态的,否则返回 null。为了修复它,为静态字段创建了一个非静态设置器,并在该设置器上方应用了@Value。

于 2016-10-25T19:56:09.470 回答
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 属性进行依赖注入。

于 2008-11-25T17:22:27.717 回答
4

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

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

于 2009-12-17T14:28:28.540 回答
2

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

大多数人都知道您可以使用@Autowired 来告诉Spring 在加载应用程序上下文时将一个对象注入另一个对象。一个鲜为人知的信息块是您还可以使用 @Value 注释将属性文件中的值注入到 bean 的属性中。有关更多信息,请参阅此帖子...

Spring 3.0 中的新内容 || 自动装配 bean 值 || 春季自动装配属性值

于 2013-01-02T12:39:35.360 回答
2

对我来说,这是@Lucky 的回答,特别是这行

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

船长调试页面

这解决了我的问题。我有一个从命令行运行的基于 ApplicationContext 的应用程序,从 SO 上的一些评论来看,Spring 将这些与基于 MVC 的应用程序不同地连接起来。

于 2013-06-18T04:40:00.170 回答
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) {
            ...
        }
    }
}
于 2016-10-20T18:31:47.180 回答
0

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

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

  • 配置 PreProd 和 Prod 系统的首选项
  • “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

亲切的问候,
哈拉尔

于 2013-03-13T18:05:50.813 回答
0

Spring 5 中最简单的方法是在@ConfigurationProperties这里使用示例 https://mkyong.com/spring-boot/spring-boot-configurationproperties-example/

于 2020-06-29T08:11:11.607 回答
-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://localhost:3306/addvertisement

dev.app.jdbc.username=root

dev.app.jdbc.password=root

于 2014-04-19T16:52:27.497 回答