Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何将属性值注入到使用注释配置的Springbean中?_Java_Spring_Dependency Injection - Fatal编程技术网

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

Java 如何将属性值注入到使用注释配置的Springbean中?,java,spring,dependency-injection,Java,Spring,Dependency Injection,我有一堆SpringBean,它们是通过注释从类路径中获取的,例如 @Repository("personDao") public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao { // Implementation omitted } 在Spring XML文件中,定义了: 我想将app.properites中的一个属性注入到上面显示的bean中。我不能简单地做这样的事情 因为Personda

我有一堆SpringBean,它们是通过注释从类路径中获取的,例如

@Repository("personDao")
public class PersonDaoImpl extends AbstractDaoImpl implements PersonDao {
    // Implementation omitted
}
在Spring XML文件中,定义了:


我想将app.properites中的一个属性注入到上面显示的bean中。我不能简单地做这样的事情


因为PersondaImpl在SpringXML文件中没有特性(它是通过注释从类路径中获取的)。我已经做到了以下几点:

@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
访问我感兴趣的属性?

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

另一种选择是添加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>

${results.max}
检索时,此bean可以转换为
java.util.Properties
,其中将包含名为
results.max
的属性,其值从
app.Properties
读取。同样,这个bean可以通过@Resource注释(作为java.util.Properties的实例)被注入到任何类中


就个人而言,我更喜欢这个解决方案(而不是我提出的另一个),因为您可以精确限制appProperties公开哪些属性,并且不需要读取app.properties两次。

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

要同时拥有可自动连接的属性Bean和属性配置器,您可以编写:

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

类路径:live.properties
类路径:development.properties
并引用PropertyConfigure中的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 "";
}
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);
                    }
                }
            }
        }
    }

}
属性注释和占位符配置器如下所示:

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.METHOD, ElementType.FIELD})
public @interface Property {
    String key();
    String defaultValue() default "";
}
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);
                    }
                }
            }
        }
    }

}

您可以随意修改来品尝

在Spring 3.0.0M3中有一个新的注释
@Value
@Value
不仅支持
{…}
表达式,还支持
${…}
占位符

如果无法使用Spring2.5,则可以为每个属性定义一个bean,并使用限定符注入它们。像这样:

  <bean id="someFile" class="java.io.File">
    <constructor-arg value="${someFile}"/>
  </bean>

它的可读性不是很好,但它完成了任务。

我个人喜欢Spring 3.0中的这种新方式:

没有能手或二传手

通过配置加载属性时:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
      p:location="classpath:propertyFile.properties" name="propertiesBean"/>
是与PropertyPlaceHolderConfigure等价的XML

例如: applicationContext.xml

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

将属性值自动关联到SpringBean中:

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

||
||

如果您需要更灵活的配置,请尝试设置4JPlaceHolderConfiguration:

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

  • 配置预处理和生产系统的首选项
  • “mvn jetty:run”的首选项和JNDI环境变量(JNDI覆盖首选项)
  • UnitTests的系统属性(@BeforeClass注释)
首先检查键值源的默认顺序如所述:

它可以通过类路径中的setings4j.xml(精确到log4j.xml)进行定制

让我知道你的意见:设置4J-user@lists.sourceforge.net

带着友好的问候,

哈拉尔德

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

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

这解决了我的问题。我有一个基于ApplicationContext的应用程序在命令行中运行,根据大量的评论判断,Spring将这些应用程序与基于MVC的应用程序进行了不同的连接。

使用Spring的“PropertyPlaceHolderConfigure”类

一个显示动态读取为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> 

/WEB-INF/classes/config_properties/dev/database.properties
属性文件

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

您还可以为类添加注释:

@PropertySource("classpath:/com/myProject/config/properties/database.properties")
有这样一个变量:

@Autowired
private Environment env;
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());
@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) {
            ...
        }
    }
}
现在,您可以通过以下方式访问所有属性:

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

如前所述,
@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;
还可以为基本类型设置值

@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;
    }
}
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 id="Bean1" class="org.some.beans.MyBean">
    <property name="id" value="1"/>
    <property name="name" value="MyBean"/>
</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) {
            ...
        }
    }
}
java.util.Properties props = System.getProperties().getProperty("propertyName");