6

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

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

或者有没有办法placeholderConfig稍后初始化bean?我尝试为这个 bean 使用depends-on,lazy-init属性,但没有帮助。提前致谢。

4

6 回答 6

6

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

如果你有不止一个<jdbc:initialize-database />适应#0.

于 2014-01-29T10:52:11.573 回答
5

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

于 2012-11-13T12:37:19.797 回答
3

这个脚本

<?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 无法验证我的模式。

于 2017-01-27T12:09:30.633 回答
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
于 2013-01-03T11:11:32.297 回答
0

我们的用例可以说更加复杂。我们使用flyway进行数据库迁移,它需要在entityManagerFactory创建之前启动。对我们而言,问题在于<jdbc:initialize-database />它仅在我们的迁移测试中使用,因此在flywayentityManagerFactory. 所以我们不能简单地使用L. BIZE答案并让我们的flywaybean 依赖,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>

当bean 存在时才OptionalBeanInitializer负责初始化org.springframework.jdbc.datasource.init.DataSourceInitializer#0bean 。

于 2015-09-06T06:38:33.530 回答
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>
于 2016-10-05T08:54:11.460 回答