我正在构建一个基于DropWizard的应用程序,它将具有嵌入式Derby数据库。
Dropwizard框架中的哪个位置是测试数据库是否存在以及是否存在的适当位置。
现在我正在DataSourceFactory
模块提供的.yml
文件中配置数据库,并且在dropwizard-db
方法之前不可用调用。
我在这个应用程序中也使用Guice,因此也会接受涉及Guice的解决方案。
答案 0 :(得分:2)
如我所知,我将提供我的解决方案。背景故事,我正在使用guicey(https://github.com/xvik/dropwizard-guicey),在我看来,这是一个很棒的框架。我用它来与guice集成,但是我希望大多数实现都是类似的并且可以采用。除此之外,我还使用liquibase进行数据库检查和一致性。
首先,在初始化期间,我正在创建一个包,为我做验证。这个捆绑是一个guicey概念。它将在guice初始化期间自动运行。这个包看起来像这样:
/**
* Verifying all changelog files separately before application startup.
*
* Will log roll forward and roll back SQL if needed
*
* @author artur
*
*/
public class DBChangelogVerifier extends ComparableGuiceyBundle {
private static final String ID = "BUNDLEID";
private static final Logger log = Logger.getLogger(DBChangelogVerifier.class);
private List<LiquibaseConfiguration> configs = new ArrayList<>();
public void addConfig(LiquibaseConfiguration configuration) {
this.configs.add(configuration);
}
/**
* Attempts to verify all changelog definitions with the provided datasource
* @param ds
*/
public void verify(DataSource ds) {
boolean throwException = false;
Contexts contexts = new Contexts("");
for(LiquibaseConfiguration c : configs) {
try(Connection con = ds.getConnection()) {
Database db = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(con));
db.setDatabaseChangeLogLockTableName(c.changeLogLockTableName());
db.setDatabaseChangeLogTableName(c.changeLogTableName());
Liquibase liquibase = new ShureviewNonCreationLiquibase(c.liquibaseResource(), new ClassLoaderResourceAccessor(), db);
liquibase.getLog();
liquibase.validate();
List<ChangeSet> listUnrunChangeSets = liquibase.listUnrunChangeSets(contexts, new LabelExpression());
if(!listUnrunChangeSets.isEmpty()) {
StringWriter writer = new StringWriter();
liquibase.update(contexts, writer);
liquibase.futureRollbackSQL(writer);
log.warn(writer.toString());
throwException = true;
}
} catch (SQLException | LiquibaseException e) {
throw new RuntimeException("Failed to verify database.", e);
}
}
if(throwException){
throw new RuntimeException("Unrun changesets in chengelog.");
}
}
/**
* Using init to process and validate to avoid starting the application in case of errors.
*/
@Override
public void initialize(GuiceyBootstrap bootstrap) {
Configuration configuration = bootstrap.configuration();
if(configuration instanceof DatasourceConfiguration ) {
DatasourceConfiguration dsConf = (DatasourceConfiguration) configuration;
ManagedDataSource ds = dsConf.getDatasourceFactory().build(bootstrap.environment().metrics(), "MyDataSource");
verify(ds);
}
}
@Override
public String getId() {
return ID;
}
}
请注意,ComparableGuiceBundle是我添加的界面,因此我可以在捆绑包及其init函数中订购。
此捆绑包将由guicey自动初始化,并且将调用init方法,为我提供数据源。在init(同一个线程)我调用验证。这意味着,如果验证失败,我的应用程序启动失败,它将拒绝完成启动。
在我的启动代码中,我只是将此捆绑包添加到Guicey配置中,以便Guice可以了解它:
// add all bundles to the bundles variable including the Liquibase bundle.
// registers guice with dropwizard
bootstrap.addBundle(GuiceBundle.<EngineConfigurationImpl>builder()
.enableAutoConfig("my.package")
.searchCommands(true)
.bundles(bundles.toArray( new GuiceyBundle[0]))
.modules(getConfigurationModule(), new CoreModule())
.build()
);
这就是我需要做的一切。 Guicey负责其余的工作。在应用程序启动期间,它将初始化传递给它的所有包。由于它具有可比性,验证我的数据库的包是第一个,将首先执行。只有当该捆绑包成功启动时,其他捆绑包才会启动。
对于liquibase部分:
public void verify(DataSource ds) {
boolean throwException = false;
Contexts contexts = new Contexts("");
for(LiquibaseConfiguration c : configs) {
try(Connection con = ds.getConnection()) {
Database db = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(con));
db.setDatabaseChangeLogLockTableName(c.changeLogLockTableName());
db.setDatabaseChangeLogTableName(c.changeLogTableName());
Liquibase liquibase = new ShureviewNonCreationLiquibase(c.liquibaseResource(), new ClassLoaderResourceAccessor(), db);
liquibase.getLog();
liquibase.validate();
List<ChangeSet> listUnrunChangeSets = liquibase.listUnrunChangeSets(contexts, new LabelExpression());
if(!listUnrunChangeSets.isEmpty()) {
StringWriter writer = new StringWriter();
liquibase.update(contexts, writer);
liquibase.futureRollbackSQL(writer);
log.warn(writer.toString());
throwException = true;
}
} catch (SQLException | LiquibaseException e) {
throw new RuntimeException("Failed to verify database.", e);
}
}
if(throwException){
throw new RuntimeException("Unrun changesets in chengelog.");
}
}
从我的设置中可以看出,我可以有多个可以检查的更改日志配置。在我的启动代码中,我查找它们并将它们添加到捆绑包中。
Liquibase将为您选择正确的数据库。如果没有可用的数据库,则会出错。如果连接未启动,则会出错。
如果找到unran changesets,它将打印出前滚和回滚SQL。如果md5sum不正确,它将打印出来。在任何情况下,如果数据库与变更集不一致,它将拒绝启动。
现在在我的情况下,我不希望liquibase创建任何东西。这是一个纯粹的验证过程。但是,liquibase确实为您提供了运行所有更改集,创建表等的选项。您可以在文档中阅读它。这是相当直接的。
这种方法几乎将liquibase与正常启动集成在一起,而不是使用带有dropwizard的数据库命令来手动执行它们。
我希望有帮助,如果您有任何疑问,请与我联系。
阿图尔