I am trying to load properties from database. I got successful in that. But now problem is that, for dataSource bean, i want to use placeholders. Please see applicationProperties.xml file, then one can get idea:
<!-- 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>
The above code is for loading properties from DB. now as you can see for dataSource bean, there are some placeholders used. So i included this line at top:
<context:property-placeholder location="classpath:databaseForConfiguration.properties"/>
databaseForConfiguration.properties contains all required properties and is in classpath :
driverClassName=org.postgresql.Driver
url=jdbc:postgresql://localhost:5432/mydb
username=user
password=pass
But when i try to execute, i get following exception:
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
and similar for {url}, {username},{password}.
As it's simple to understand, that for PropertiesUtil bean to initialize, first dataSource bean need to initialize. And for dataSource bean, local properties placeholders must be there. Which in this case, not getting.
I want both these things, load placeholders from local files and also from database.
Anyone please help me to resolve this problem.
thanks in advance.
Spring Boot Framework comes with a built-in mechanism for application configuration using a file called application. properties. It is located inside the src/main/resources folder, as shown in the following figure.
For
<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>
I created factory for datasource. and now it's look like this:
<bean id="dataSource" class="core.factory.DataSourceFactory" factory-method="createDataSource">
<constructor-arg type="java.lang.String" value="DBConfig.properties" />
</bean>
The DataSourceFactory class look like this:
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;
}
}
Now i am able to get properties from local file as well as database, too.
Regarding another problem i put in comments, which was to load i18n resources from database,i got solution from this link: Spring MVC: Database MessageSource fall back to properties file.
I myself posted question and now i got solution. Hope this will be useful for someone.
First of all you missunderstood <context:property-placeholder>
. Its location
is for file
, not Properties
object.
Right, your databaseForConfiguration.properties
contains a Properties
object from DB, but it isn't a .properties
file.
So, try this:
<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"/>
From other side it isn't clear how you are going to load properties from DB, if you try to use placeholders
for DataSource
options. In this case you already should already have a configured <context:property-placeholder>
...
UPDATE
There is reason to mix several answers from different topics. Asn I've shown above the MethodInvokingFactoryBean
does the stuff to build Properties
object.
If your <context:property-placeholder>
can't resolve placeholders (Could not load JDBC driver class [${driverClassName}]
), then it doesn't see your databaseForConfiguration.properties
in the classpath.
Be sure to use correct location
value, e.g. location="classpath:WEB-INF/databaseForConfiguration.properties"
, if your file is there with WAR.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With