【问题标题】:Spring : Loading Properties from Database and local filesSpring:从数据库和本地文件加载属性
【发布时间】:2014-07-29 15:49:04
【问题描述】:

我正在尝试从数据库加载属性。我在这方面取得了成功。 但现在的问题是,对于 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>

以上代码用于从数据库加载属性。现在您可以看到 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,必须有本地属性占位符。 在这种情况下,没有得到。

我想要这两样东西从本地文件加载占位符也从数据库加载

请任何人帮我解决这个问题。

提前致谢。

【问题讨论】:

    标签: spring


    【解决方案1】:

    对于

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

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

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

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

    【讨论】:

    • 你好@Jaydeep .. 这是你发布的一个很好的解决方案。我们可以找到完整源代码的任何地方。这将是一个很大的帮助......
    【解决方案2】:

    首先你误解了&lt;context:property-placeholder&gt;。它的location 用于file,而不是Properties 对象。

    对,您的 databaseForConfiguration.properties 包含来自 DB 的 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 选项,则从另一方面来看,您将如何从数据库加载属性尚不清楚。在这种情况下,您应该已经配置了&lt;context:property-placeholder&gt;...

    更新

    有理由混合来自不同主题的多个答案。我在上面显示的 MethodInvokingFactoryBean 负责构建 Properties 对象。

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

    确保使用正确的location 值,例如location="classpath:WEB-INF/databaseForConfiguration.properties",如果您的文件与 WAR 一起存在。

    【讨论】:

    • 没有。对不起。你误会了。 databaseForConfiguration.properties 是属性文件。(我现在编辑了上面的问题,你可以看到)。为了从数据库加载属性,我混合了几个站点的逻辑。首先我从link 那里得到了帮助。而不是将属性暴露给 java 类,我提到了link
    • 感谢您的更正 (+1)。我已经根据新信息更新了我的答案。
    • 感谢您的建议。这可能会帮助其他人。我也得到知识。但我的问题很难解释,但现在我以其他方式解决了它。如果您有另一种从数据库加载属性的解决方案,请提供。我想申请 i18n,为此你知道需要属性文件。所以我想从数据库加载而不是文件。那么如何从数据库中加载 i18n 属性呢?我的数据库表结构应该如何?提前致谢。
    猜你喜欢
    • 2018-07-21
    • 1970-01-01
    • 2013-05-04
    • 2020-04-14
    • 2017-11-17
    • 1970-01-01
    • 2015-12-07
    • 1970-01-01
    • 2017-04-05
    相关资源
    最近更新 更多