Spring:从数据库和本地文件加载属性

时间:2014-06-09 06:14:58

标签: spring

我正在尝试从数据库加载属性。我成功了。 但现在的问题是,对于dataSource bean,我想使用占位符。 请参阅applicationProperties.xml文件,然后就可以了解:

<!-- Data Source Bean -->
<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${driverClassName}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
</bean>

<!-- My Own class for managing properites came from Database -->
<bean class="PropFromDB.PropFromDB.PropertiesUtil" >
    <property name="propertiesArray">
        <list>
            <ref bean="propertiesFromDB" />
        </list>
    </property>
</bean>

<!-- PropertiesFactoryBean bean -->
<bean id="propertiesFromDB"
    class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="properties" ref="commonsConfigurationFactoryBean" />
</bean>

<!-- CommonsConfigurationFactoryBean bean -->
<bean id="commonsConfigurationFactoryBean"
        class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
    <constructor-arg ref="databaseConfiguration"></constructor-arg>
</bean>

<!-- DatabaseConfiguration bean -->
<bean name="databaseConfiguration" 
    class="org.apache.commons.configuration.DatabaseConfiguration">
    <constructor-arg index="0" ref="dataSource" />
    <constructor-arg index="1" value="properties" />
    <constructor-arg index="2" value="key" />
    <constructor-arg index="3" value="value" />
</bean>

以上代码用于从DB加载属性。现在正如您可以看到的dataSource bean,使用了一些占位符。所以我把这行包括在最上面:

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

databaseForConfiguration.properties 包含所有必需的属性在类路径中

driverClassName=org.postgresql.Driver
url=jdbc:postgresql://localhost:5432/mydb
username=user
password=pass

但是当我尝试执行时,我得到以下异常:

 Caused by: org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.MethodInvocationException: Property 'driverClassName' threw exception; nested exception is java.lang.IllegalStateException: Could not load JDBC driver class [${driverClassName}]
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:108)
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:62)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1489)
    ... 60 more

类似 {url} {username} {password}

由于它易于理解,对于要初始化的PropertiesUtil bean,首先需要初始化dataSource bean。对于dataSource bean,必须存在本地属性占位符。 在这种情况下,没有得到。

我希望这两件事从本地文件加载占位符也从数据库加载

任何人都可以帮我解决这个问题。

提前感谢。

2 个答案:

答案 0 :(得分:8)

对于

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${driverClassName}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
</bean>

我为数据源创建了工厂。现在它看起来像这样:

<bean id="dataSource" class="core.factory.DataSourceFactory" factory-method="createDataSource">
        <constructor-arg type="java.lang.String" value="DBConfig.properties" />
     </bean>

DataSourceFactory类如下所示:

public class DataSourceFactory
{

    private static final String DRIVER_CLASS_NAME = "db.driver";
    private static final String URL = "db.url";
    private static final String URL_LOGDB = "logdb.url";
    private static final String USER_NAME = "db.username";
    private static final String PASSWORD = "db.password";

    public static DataSource createDataSource(String propertyFilename) throws IOException
    {
        Properties properties = getProperties(propertyFilename);
        return getDataSource(URL, properties);
    }

    public static DataSource createDataSourceForLogDb(String propertyFilename) throws Exception
    {
        Properties properties = getProperties(propertyFilename);
        return getDataSource(URL_LOGDB, properties);
    }

    private static Properties getProperties(final String fileName) throws IOException
    {
        Properties properties = new Properties();
        InputStream in = DataSourceFactory.class.getClassLoader().getResourceAsStream(fileName);
        properties.load(in);
        in.close();
        return properties;
    }

    private static DataSource getDataSource(final String url, final Properties properties)
    {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(properties.getProperty(DRIVER_CLASS_NAME));
        dataSource.setUrl(properties.getProperty(url));
        dataSource.setUsername(properties.getProperty(USER_NAME));
        dataSource.setPassword(properties.getProperty(PASSWORD));
        return dataSource;
    }
}

现在我也可以从本地文件和数据库中获取属性。

关于我在评论中提出的另一个问题,即从数据库加载i18n资源,我从这个链接获得了解决方案:Spring MVC: Database MessageSource fall back to properties file

我自己发布了问题,现在我得到了解决方案。 希望这对某人有用。

答案 1 :(得分:6)

首先,你错过了<context:property-placeholder>。其location适用于file,而非Properties对象。

是的,您的databaseForConfiguration.properties包含来自数据库的Properties对象,但它不是.properties文件。

所以,试试这个:

<bean id="myProperties" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
      p:staticMethod="org.apache.commons.configuration.ConfigurationConverter.getProperties"
      p:arguments-ref="databaseConfiguration"/>

<context:property-placeholder properties-ref="myProperties"/>

从另一方面来看,如果您尝试将placeholders用于DataSource选项,则不清楚如何从数据库加载属性。在这种情况下,您已经应该已经配置了<context:property-placeholder> ...

<强>更新

有理由混合来自不同主题的几个答案。我已经在MethodInvokingFactoryBean上面显示了构建Properties对象的东西。

如果您的<context:property-placeholder>无法解析占位符(Could not load JDBC driver class [${driverClassName}]),则它在类路径中看不到您的databaseForConfiguration.properties

请务必使用正确的location值,例如location="classpath:WEB-INF/databaseForConfiguration.properties",如果您的文件带有WAR。