如何在运行时添加属性并使用它们填充上下文文件中的占位符?
首先,有一点背景知识:我有一个加载数据库的批处理数据加载器。我要求该程序的数据库密码不存储在磁盘上,因此我允许用户以交互方式输入它。 我正在使用 hibernate,我的数据源是在上下文文件中配置的,实际参数在另一个属性文件中。
我正在寻找的一些属性
- 该属性仅在运行时可用(用户输入密码)
- 可以在上下文加载之前提供
- 不需要动态改变
- 其他相关属性仍通过普通属性文件加载
db.xml:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${hibernate.connection.driver_class}" />
<property name="url" value="${hibernate.connection.url}" />
<property name="username" value="${hibernate.connection.username}" />
<property name="password" value="${hibernate.connection.password}" />
and so on...
</bean>
数据库.属性:
hibernate.connection.username=Username
### hibernate.connection.password= #don't want the password stored
hibernate.connection.url=<the url>
hibernate.connection.driver_class=oracle.jdbc.driver.OracleDriver
还有我的主要context.xml:
<import resource="classpath:db.xml" />
<context:property-placeholder location="classpath:database.properties" />
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:database.properties" />
</bean>
plus more...
我想要做的是在运行时刷新上下文之前向上下文中添加一个新属性(hibernate.connection.password
),以便在 db.xml< 中替换相应的值
.
我当前的尝试如下
Properties prop = new Properties();
prop.setProperty("hibernate.connection.password", thePassword);
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setProperties(prop);
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {"my-context.xml"}, false); // Don't refresh after loading
ctx.addBeanFactoryPostProcessor(ppc);
ctx.refresh();
但是,我一定做错了什么,因为我收到一个异常,告诉我 database.properties
文件中的属性没有被使用。
2016-03-14 14:58:41 WARN ClassPathXmlApplicationContext:546 - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'dataSource' defined in class path resource [db.xml]: Could not resolve placeholder 'hibernate.connection.driver_class' in string value "${hibernate.connection.driver_class}"; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'hibernate.connection.driver_class' in string value "${hibernate.connection.driver_class}"
为了确保我对database.properties文件的设置正确,如果我删除对ctx.addBeanFactoryPostProcessor(ppc)
的调用,我会收到一个异常,提示缺少密码
2016-03-14 16:52:10 WARN ClassPathXmlApplicationContext:546 - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanDefinitionStoreException: Invalid bean definition with name 'dataSource' defined in class path resource [db.xml]: Could not resolve placeholder 'hibernate.connection.password' in string value "${hibernate.connection.password}"; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'hibernate.connection.password' in string value "${hibernate.connection.password}"
Error: Invalid bean definition with name 'dataSource' defined in class path resource [db.xml]: Could not resolve placeholder 'hibernate.connection.password' in string value "${hibernate.connection.password}"; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'hibernate.connection.password' in string value "${hibernate.connection.password}"
如果密码存在于属性文件中,则一切正常。
我的问题是如何使database.properties和运行时定义的属性都后处理我的上下文文件?
编辑
我发现的一个解决方案是手动将属性文件加载到 PropertyPlaceholderConfigurer 中。
ppc.setLocation(new ClassPathResource("database.properties"));
这是可行的,但是以编程方式设置的属性将被属性文件中的任何匹配属性覆盖,这使得它感觉像是一种解决方法。另外,我仍然不明白为什么两个 PropertyPlaceholderConfigurers 都没有被使用(上下文文件中定义的一个和 java 中定义的一个)
最佳答案
为了让 Spring 从 database.properties
读取属性,您必须定义一个 Properties Placeholder 的 bean,如下所示:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>database.properties</value>
</property>
</bean>
然后您可以在 dataSource
bean 中使用它,如下所示:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${hibernate.connection.driver_class}" />
<property name="url" value="${hibernate.connection.url}" />
<property name="username" value="${hibernate.connection.username}" />
<property name="password" value="${hibernate.connection.password}" />
and so on...
</bean>
如果您想在运行时传递密码,则可以将其作为参数传递,如下所示:
-Dhibernate.connection.password=<password>
关于java - 如何在 Spring 上下文中包含运行时的属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35993870/