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

I need to execute a SQL script before the PropertyPlaceholderConfigurer is initialized in the Spring context, as soon as the application properties are stored in the database, and this script should insert them. But now the placeholder is initializing 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 a placeholderConfig bean later? I tried using the depends-on , lazy-init attributes for this bean, but that didn't help. Thanks in advance.

+4
source share
6 answers

This is how I solved it. I created the Initializer class. This class in its constructor executes simple old sql instructions ( java.sql.Statement ), creates a table (if it does not exist) and inserts properties (if they are not there). dataSource bean is passed in the context of this constructor, and the placeholderConfig bean uses depends-on="initializerBean" . Thus, properties appear in the database before they are used.

+4
source

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

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

+5
source

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> 

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 added id to the DataSourceInitializer bean. Now you can refer to it in the PropertyPlaceholderConfigurer depends-on attribute. This way you declare your PropertyPlaceholderConfigurer to be created after the DataSourceInitializer.

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

In my case, db was initialized after creating LocalContainerEntityManagerFactoryBean and Hibernate was unable to validate my schema.

+1
source

The documentation explains how to deal with these problems: http://static.springsource.org/spring/docs/3.0.0.RC3/reference/html/ch12s09.html

 12.9.1.1 Initialization of Other Components that Depend on the Database 
0
source

Our precedent was perhaps even more complex. We use flyway for data migration, and it needs to be started before creation of entityManagerFactory . The problem for us was that <jdbc:initialize-database /> was only used in our migration tests and thus was initialized in a different application context than flyway and entityManagerFactory . Therefore, we could not just use L. BIZE , and let our flyway bean depend on org.springframework.jdbc.datasource.init.DataSourceInitializer#0 , because it may not exist (i.e., it does not exist in production). We finished creating a custom factory bean as follows:

 class OptionalBeanInitializer extends AbstractFactoryBean implements BeanFactoryAware { private String beanName; private BeanFactory beanFactory; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } @Override public Class<?> getObjectType() { return OptionalBeanInitializer.class; } public void setBeanName(String beanName) { this.beanName = beanName; } @Override protected Object createInstance() throws Exception { if (beanFactory.containsBean(beanName)) { // Initialize beanFactory.getBean(beanName); } return new OptionalBeanInitializer(); } } 

What can we use to depend on our additional dependency like:

 <bean id="optionalDataSourceInitializer" class="com.xyzOptionalBeanInitializer"> <property name="beanName" value="org.springframework.jdbc.datasource.init.DataSourceInitializer#0"/> </bean> <bean id="flyway" class="com.googlecode.flyway.core.Flyway" init-method="migrate" depends-on="optionalDataSourceInitializer"> <property name="dataSource" ref="dataSource"/> </bean> <bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory" depends-on="flyway, optionalDataSourceInitializer"> <property name="dataSource" ref="dataSource"/> </bean> 

OptionalBeanInitializer will take care of initializing org.springframework.jdbc.datasource.init.DataSourceInitializer#0 bean only if it exists.

0
source

There are two simpler ways to add a dependency attribute for a test context only and not for a production context.

1 / Override the bean in the test context. In our case, there is a production context:

 <bean id="placeholderConfig" /> 

And the unit test context:

 <bean id="placeholderConfig" depends-on="org.springframework.jdbc.datasource.init.DataSourceInitializer#0" /> 

Make sure that the unit test context is loaded before the production context, and after the jdbc: initialize-database database initialization phase has been created, a good placeholderConfig bean will be added.

2 / Another way is to use profiles

 <beans profile="!test"> <bean id="placeholderConfig" .../> </beans> <beans profile="test"> <jdbc:initialize-database data-source="dataSource" .../> <bean id="placeholderConfig" depends-on="org.springframework.jdbc.datasource.init.DataSourceInitializer#0" .../> </beans> 
0
source

Source: https://habr.com/ru/post/1445704/


All Articles