在上下文创建开始时运行<jdbc:initialize-database> </jdbc:initialize-database>

时间:2012-11-13 07:46:55

标签: java spring properties

我需要在Spring的上下文中初始化SQL之前执行PropertyPlaceholderConfigurer脚本,只要应用程序属性存储在数据库中并且此脚本应插入它们。但是目前占位符是先前初始化的,这会导致错误。

有没有办法在Spring <jdbc:initialize-database data-source="dataSource" ...之前执行<bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" ...

或者有没有办法在以后初始化placeholderConfig bean?我试图为这个bean使用depends-onlazy-init属性,但它没有帮助。提前谢谢。

6 个答案:

答案 0 :(得分:5)

以下是我解决这个问题的方法。我创建了一个类Initializer。该类在其构造函数中执行普通的旧sql语句(java.sql.Statement),创建表(如果它不存在),并插入属性(如果它们不存在)。 dataSource bean在上下文中传递给此构造函数,placeholderConfig bean使用depends-on="initializerBean"。因此,属性在使用之前会显示在数据库中。

答案 1 :(得分:5)

另一种没有创建任何Bean的解决方案: 如果您有一个<jdbc:initialize-database />,则可以将此属性depends-on="org.springframework.jdbc.datasource.init.DataSourceInitializer#0"添加到您的bean <bean id="placeholderConfig" />

如果您有多个<jdbc:initialize-database />调整#0

答案 2 :(得分:1)

此脚本

<?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>

本质上是

的捷径
<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>

请注意,我已将id添加到DataSourceInitializer bean。现在,您可以在PropertyPlaceholderConfigurer的depends-on属性中引用它。这样就宣布你的PropertyPlaceholderConfigurer应该在DataSourceInitializer之后创建。

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

在我的例子中,在创建了LocalContainerEntityManagerFactoryBean并且Hibernate无法验证我的架构之后初始化了db。

答案 3 :(得分:0)

文档说明了如何处理这些问题: 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

答案 4 :(得分:0)

我们的用例可能更复杂。我们使用flyway进行数据库迁移,需要在创建entityManagerFactory之前启动它。我们面临的问题是<jdbc:initialize-database />仅用于我们的迁移测试,因此在flywayentityManagerFactory之间的不同应用程序环境中初始化。所以我们不能简单地使用L. BIZE回答让我们的flyway bean依赖于org.springframework.jdbc.datasource.init.DataSourceInitializer#0因为它可能不存在(即在生产中它不存在)。我们最终创建了一个这样的自定义工厂bean:

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

我们可以使用哪个依赖于我们的可选依赖项:

<bean id="optionalDataSourceInitializer" class="com.x.y.z.OptionalBeanInitializer">
       <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将负责初始化org.springframework.jdbc.datasource.init.DataSourceInitializer#0 bean (如果存在)。

答案 5 :(得分:0)

有两种更简单的方法可以仅为测试上下文添加依赖属性,而不是为生产上下文添加。

1 /在测试上下文中覆盖bean。 在我们的例子中,这里是生产环境:

<bean id="placeholderConfig" />

单元测试环境:

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

在jdbc:initialize-database阶段之后,确保在生产上下文和好的placeholderConfig bean之前加载单元测试上下文。

2 /另一种方法是使用配置文件

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