我怎样才能注入一个属性值到使用注释configuration的Spring Bean?
我有一堆Spring类,通过注释从classpath中获取,例如
@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文件中(它是通过注释从类path中获取的)。 我有以下几点:
@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
访问我感兴趣的房产?
您可以使用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;
这里是我写了一个博客文章了解更多信息。
就我个人而言,我喜欢Spring 3.0中的这个新方法:
private @Value("${propertyName}") String propertyField;
没有获得者或制定者!
通过configuration加载属性:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="classpath:propertyFile.properties" name="propertiesBean"/>
为了进一步激发我的兴趣,我甚至可以在IntelliJ中控制单击ELexpression式,并将其带到属性定义中!
还有完全非xml版本 :
@PropertySource("classpath:propertyFile.properties") public class AppConfig { @Bean public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); }
Spring 3.0.0M3中有一个新的注解@Value 。 @Value
不仅支持#{...}
expression式,而且还支持${...}
占位符
<context:property-placeholder ... />
是与PropertyPlaceholderConfigurer等效的XML。
例如:applicationContext.xml
<context:property-placeholder location="classpath:test.properties"/>
组件类
private @Value("${propertyName}") String propertyField;
另一种方法是添加如下所示的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注解dependency injection(作为java.util.Properties的一个实例)到任何类中。
就个人而言,我更喜欢这个解决scheme(对我build议的其他解决scheme),因为您可以限制appProperties公开哪些属性,并且不需要读取app.properties两次。
我需要有两个属性文件,一个用于生产和一个覆盖开发(这将不会被部署)。
要同时拥有一个可以自动assembly的属性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>
在我们得到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); } } } } } }
随意修改品尝
spring的方式:
private @Value("${propertyName}") String propertyField;
是使用Spring的“PropertyPlaceholderConfigurer”类注入值的新方法。 另一种方式是打电话
java.util.Properties props = System.getProperties().getProperty("propertyName");
注意:对于@Value,您不能使用static propertyField,它应该是非静态的,否则返回null。 为了解决这个问题,我们为静态字段创build了一个非静态的setter,并且在这个setter上面应用了@Value。
一个可能的解决scheme是声明第二个从相同的属性文件读取的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的types为java.util.Properties,可以使用上面显示的@Resource属性进行dependency injection。
你也可以注释你的课堂:
@PropertySource("classpath:/com/myProject/config/properties/database.properties")
并有一个像这样的variables:
@Autowired private Environment env;
现在你可以通过这种方式访问你的所有属性:
env.getProperty("database.connection.driver")
如果你使用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) { ...
它不是超级可读的,但它完成了工作。
正如上面提到的@value
做这个工作,它是相当灵活的,因为你可以有springEL在里面。
以下是一些可能有用的示例:
//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;
您还可以设置原始types的值。
@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;
将属性值自动assembly成春豆:
大多数人知道你可以使用@Autowired来告诉Spring在加载应用程序上下文时将一个对象注入到另一个对象中。 一个鲜为人知的信息块就是你也可以使用@Value注解来将属性文件中的值注入到bean的属性中。 看到这个职位的更多信息…
Spring 3.0中的新东西 || 自动assemblybean值 || 自动assembly属性值在spring
对我来说,这是@幸运的答案,特别是线条
AutowiredFakaSource fakeDataSource = ctx.getBean(AutowiredFakaSource.class);
从队长debugging页面
这解决了我的问题。 我有一个从命令行运行的基于ApplicationContext的应用程序,通过一些关于SO的评论来判断,Spring将这些应用程序与MVC应用程序区分开来。
如果您需要更多的configuration灵活性,请尝试Settings4jPlaceholderConfigurer: http : //settings4j.sourceforge.net/currentrelease/configSpringPlaceholder.html
在我们的应用程序中使用:
- configurationPreProd和Prod系统的首选项
- 首选项和JNDI环境variables(JNDI覆盖首选项)“mvn jetty:run”
- UnitTests的系统属性(@BeforeClass注解)
先检查key-value-Source的默认顺序如下:
http://settings4j.sourceforge.net/currentrelease/configDefault.html
可以在你的类path中使用settings4j.xml(精确到log4j.xml)进行自定义。
让我知道你的意见:settings4j-user@lists.sourceforge.net
以友好的问候,
哈拉尔
我认为将属性注入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) { ... } } }
使用Spring的“PropertyPlaceholderConfigurer”类
一个简单的例子显示属性文件dynamic读取为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 =根
- 为什么我需要一个IoC容器而不是简单的DI代码?
- Autofac – InstancePerHttpRequest与InstancePerLifetimeScope
- Android和dependency injection
- dependency injection和JavaFX
- 依赖地狱 – 如何将依赖关系传递给深度嵌套的对象?
- 为什么$只在'angular.mock.module'函数中可用,$ q只在'angular.mock.inject'函数中可用?
- 为什么要使用dependency injection?
- Spring属性(属性占位符)自动assembly
- 如何在dependency injection中使用log4net