我需要在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
属性,但它没有帮助。提前谢谢。
答案 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 />
仅用于我们的迁移测试,因此在flyway
和entityManagerFactory
之间的不同应用程序环境中初始化。所以我们不能简单地使用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>