Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running <jdbc:initialize-database> at the beginning of context creation

I need to execute SQL script before PropertyPlaceholderConfigurer is initialized in Spring's context, as soon as application properties are stored in the database and this script should insert them. But currently placeholder is initialized earlier, which leads to errors.

Is there a way to execute <jdbc:initialize-database data-source="dataSource" ... before <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" ... in Spring?

Or is there a way to initialize placeholderConfig bean later? I tried to use depends-on, lazy-init attributes for this bean, but it didn't help. Thanks in advance.

like image 423
John Doe Avatar asked Nov 13 '12 07:11

John Doe


3 Answers

Another solution without creating any Bean: If you've got one <jdbc:initialize-database /> you can add this property depends-on="org.springframework.jdbc.datasource.init.DataSourceInitializer#0" to your bean <bean id="placeholderConfig" />

If you have more than one <jdbc:initialize-database /> adapt the #0.

like image 170
L. BIZE Avatar answered Nov 07 '22 11:11

L. BIZE


Here is how I solved that. I created a class Initializer. This class in its constructor executes plain old sql statements (java.sql.Statement), creates table (if it doesn't exist), and inserts properties (if they are not there). The dataSource bean is passed in the context to this constructor, and placeholderConfig bean uses depends-on="initializerBean". So, properties appear in the database before they are used.

like image 24
John Doe Avatar answered Nov 07 '22 10:11

John Doe


This script

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:jdbc="http://www.springframework.org/schema/jdbc"
       xsi:schemaLocation="http://www.springframework.org/schema/jdbc">


    <jdbc:initialize-database data-source="dataSource">
        <jdbc:script location="classpath:database/drop_schema.sql" />
        <jdbc:script location="classpath:database/create_schema.sql" />
        <jdbc:script location="classpath:database/sample_data.sql"/>
    </jdbc:initialize-database>
    <!-- Other bean definitions -->
</bean>

is essentially a shortcut to

<bean class="org.springframework.jdbc.datasource.init.DataSourceInitializer" id="dataSourceInitializer">
    <property name="databasePopulator" ref="resourceDatabasePopulator"/>
    <property name="dataSource" ref="dataSource"/>
</bean>
<bean id="resourceDatabasePopulator"
      class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator">
    <property name="scripts">
        <array>
            <value>classpath:database/drop_schema.sql</value>
            <value>classpath:database/create_schema.sql</value>
            <value>classpath:database/sample_data.sql</value>
        </array>
    </property>
</bean>

Note that I've added id to the DataSourceInitializer bean. Now you can reference it in PropertyPlaceholderConfigurer's depends-on attribute. That way you declare that your PropertyPlaceholderConfigurer should be created after DataSourceInitializer.

<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" depends-on="dataSourceInitializer"/>

In my case db was initialized after the LocalContainerEntityManagerFactoryBean had been created and Hibernate was unable to validate my schema.

like image 3
Valya Avatar answered Nov 07 '22 11:11

Valya